Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 螺纹、ansi c信号和Qt_Multithreading_Qt_Signals - Fatal编程技术网

Multithreading 螺纹、ansi c信号和Qt

Multithreading 螺纹、ansi c信号和Qt,multithreading,qt,signals,Multithreading,Qt,Signals,我正在编写一个基于多线程插件的应用程序。我不会成为插件的作者。因此,我希望避免主要应用程序因插件中的分段错误而崩溃。可能吗?或者插件中的崩溃肯定会影响主应用程序的状态? 我使用qt编写了一个草图程序,因为我的“真实”应用程序强烈地基于qt库。正如您所看到的,我强制线程在未分配的QString上调用修剪函数时崩溃。信号处理程序被正确调用,但在线程被迫退出后,主应用程序也会崩溃。我做错什么了吗?或者就像我之前说的,我正在努力做的是无法实现的? 请注意,在这个简化版本的程序中,我避免使用插件,而只使用

我正在编写一个基于多线程插件的应用程序。我不会成为插件的作者。因此,我希望避免主要应用程序因插件中的分段错误而崩溃。可能吗?或者插件中的崩溃肯定会影响主应用程序的状态? 我使用qt编写了一个草图程序,因为我的“真实”应用程序强烈地基于qt库。正如您所看到的,我强制线程在未分配的QString上调用修剪函数时崩溃。信号处理程序被正确调用,但在线程被迫退出后,主应用程序也会崩溃。我做错什么了吗?或者就像我之前说的,我正在努力做的是无法实现的? 请注意,在这个简化版本的程序中,我避免使用插件,而只使用线程。我想,引入插件将增加一个新的关键级别。我想一步一步走下去。总的来说,我想知道我的目标是否可行。非常感谢大家给我的任何帮助或建议

#include <QString>
#include <QThread>
#include<csignal>
#include <QtGlobal>
#include <QtCore/QCoreApplication>


class MyThread : public QThread
{
public:
    static void sigHand(int sig)
    {
        qDebug("Thread crashed");
        QThread* th = QThread::currentThread();
        th->exit(1);
    }

    MyThread(QObject * parent = 0)
    :QThread(parent)
    {
        signal(SIGSEGV,sigHand);
    }

    ~MyThread()
    {
        signal(SIGSEGV,SIG_DFL);
        qDebug("Deleted thread, restored default signal handler");
    }

    void run()
    {
        QString* s;
        s->trimmed();
        qDebug("Should not reach this point");
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    MyThread th(&a);
    th.run();
    while (th.isRunning());
    qDebug("Thread died but main application still on");
    return a.exec();
}
#包括
#包括
#包括
#包括
#包括
类MyThread:publicqthread
{
公众:
静态和(内部信号)
{
qDebug(“线程崩溃”);
QThread*th=QThread::currentThread();
th->exit(1);
}
MyThread(QObject*parent=0)
:QThread(父线程)
{
信号(SIGSEGV、sigHand);
}
~MyThread()
{
信号(SIGSEGV、SIG_DFL);
qDebug(“删除的线程,恢复的默认信号处理程序”);
}
无效运行()
{
QString*s;
s->trimmed();
qDebug(“不应达到此点”);
}
};
int main(int argc,char*argv[])
{
qcorea应用程序(argc、argv);
神话阅读(th&a);
th.run();
而(th.isRunning());
qDebug(“线程死了,但主应用程序仍在运行”);
返回a.exec();
}

我目前正在研究同一个问题,通过谷歌发现了这个问题

您的源代码不起作用有几个原因:

  • 没有新的线程。只有在调用QThread::start时,才会创建线程。而是调用MyThread::run,它在主线程中执行run方法

  • 您可以调用QThread::exit来停止线程,该线程不应该直接停止线程,而是向线程事件循环发送(qt)信号,请求它停止。因为既没有线程也没有事件循环,所以函数没有效果。即使调用了QThread::start,它也不会工作,因为编写run方法不会创建qt事件循环。为了能够对任何QThread使用exit,您需要首先调用QThread::exec。
    但是,QThread::exit无论如何都是错误的方法。为了防止SIGSEGV,必须立即调用线程,而不是在其事件循环中接收到(qt)信号之后。因此,尽管通常不赞成,但在这种情况下,必须调用QThread::terminate

  • 但通常认为,从信号处理程序调用复杂函数(如QThread::currentThread、QThread::exit或QThread::terminate)是不安全的,因此永远不要在那里调用它们

  • 由于线程仍在信号处理程序之后运行(我不确定QThread::terminate是否会足够快地终止它),信号处理程序会退出到调用它的位置,因此它会重新执行导致SIGSEGV的指令,并出现下一个SIGSEGV

因此,我使用了另一种方法,信号处理程序将包含指令地址的寄存器更改为另一个函数,该函数将在信号处理程序退出后运行,而不是崩溃指令。比如:

void signalHandler(int type, siginfo_t * si, void* ccontext){
    (static_cast<ucontext_t*>(ccontext))->Eip = &recoverFromCrash;
}

struct sigaction sa;
memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = &signalHandler; 
sigaction(SIGSEGV, &sa, 0);
ThreadBreaker是围绕QThread的一个普通包装类,因为QThread的msleep、sleep和setTerminationEnabled(必须在终止之前调用)受到保护,无法从recover函数调用


但这只是基本情况。还有很多其他的事情需要担心:捕获SIGFPE,捕获堆栈溢出(检查SIGSEGV的地址,在另一个堆栈中运行信号处理程序),为平台独立性(64位、arm、mac)定义一系列定义,显示调试消息(尝试获取堆栈跟踪,想知道为什么为它调用gdb会使X服务器崩溃,想知道为什么为它调用glibc backtrace会使程序崩溃).

我目前正在处理同一问题,并通过谷歌发现了这个问题

您的源代码不起作用有几个原因:

  • 没有新线程。只有在调用QThread::start时才会创建线程。相反,您可以调用MyThread::run,它在主线程中执行run方法

  • 您可以调用QThread::exit来停止线程,该线程不应该直接停止线程,而是发送(qt)向线程事件循环发送信号,请求其停止。由于既没有线程也没有事件循环,因此该函数无效。即使调用了QThread::start,它也不会工作,因为编写run方法不会创建qt事件循环。要能够对任何QThread使用exit,您需要先调用QThread::exec。
    然而,QThread::exit无论如何都是错误的方法。为了防止SIGSEGV,必须立即调用线程,而不是在其事件循环中接收到(qt)信号之后。因此,尽管通常不赞成,但在这种情况下,必须调用QThread::terminate

  • 但通常认为,从信号处理程序调用复杂函数(如QThread::currentThread、QThread::exit或QThread::terminate)是不安全的,因此永远不要在那里调用它们

  • 由于线程仍在信号处理程序之后运行(我不确定QThread::terminate是否会足够快地终止它),信号处理程序会退出到调用它的位置,因此它会重新执行导致SIGSEGV的指令,并出现下一个SIGSEGV

因此,我使用了不同的方法,信号处理程序更改包含指令地址的寄存器
if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
    //sub thread
    QThread* t = QThread::currentThread();
    while (programIsRunning) ThreadBreaker::sleep(1);
    ThreadBreaker::forceTerminate();
} else {
    //main thread
    while (programIsRunning) {
        QApplication::processEvents(QEventLoop::AllEvents);
        ThreadBreaker::msleep(1);
    }
    exit(0);
}