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