最近,我在这个标题中提到了这个问题。我尝试过使用 QThread::terminate(),但我无法停止线程,它处于死循环中(比如说,while(1))。
多谢。
终止线程是停止异步操作的简单解决方案,但这通常是一个坏主意:线程可能正在执行系统调用,或者在终止时可能正在更新数据结构,这可能会离开程序甚至操作系统处于不稳定状态。
尝试将您的 while(1) 转换为 while( isAlive() ) 并在您希望线程退出时使 isAlive() 返回 false。
如果 QThread 在终止期间“自然”完成,它们可能会死锁。
例如在 Unix 中,如果线程正在等待“读取”调用,则终止尝试(Unix 信号)将使“读取”调用在线程被销毁之前以错误代码中止。
这意味着线程在被终止时仍然可以到达它的自然退出点。当它这样做时,由于某些内部互斥锁已被“终止”调用锁定,因此会发生死锁。
我的解决方法是确保线程在终止后永远不会返回。
while( read(...) > 0 ) {
// Do stuff...
}
while( wasTerminated )
sleep(1);
return;
此处的wasTerminated实际上使用原子整数实现更复杂一些:
enum {
Running, Terminating, Quitting
};
QAtomicInt _state; // Initialized to Running
void myTerminate()
{
if( _state.testAndSetAquire(Running, Terminating) )
terminate();
}
void run()
{
[...]
while(read(...) > 0 ) {
[...]
}
if( !_state.testAndSetAquire(Running, Quitting) ) {
for(;;) sleep(1);
}
}
线程调用了QThread::setTerminationEnabled(false)
吗?这将导致线程终止无限期延迟。
编辑:我不知道你在哪个平台上,但我检查了 QThread::terminate 的 Windows 实现。假设线程实际上开始运行,并且没有通过上述函数禁用终止,它基本上是TerminateThread()
Windows API 中的一个包装器。此函数接受任何线程的不尊重,并且往往会留下资源泄漏和类似悬空状态的混乱。如果它没有杀死线程,那么您要么正在处理僵尸内核调用(很可能是阻塞的 I/O),要么在某个地方遇到了更大的问题。
使用未命名的管道
int gPipeFdTest[2]; //create a global integer array
当您打算创建管道时,请使用
if( pipe(gPipeFdTest) < 0)
{
perror("Pipe failed");
exit(1);
}
上面的代码将创建一个管道,它有两端 gPipeFdTest[0] 用于读取和 gPipeFdTest[1] 用于写入。您可以做的是在您的运行函数中设置为使用 select 系统调用读取管道。并且从你想跑出来的地方,那里设置写使用写系统调用。我已经使用 select 系统调用来监视管道的读取端,因为它适合我的实现。试着在你的情况下弄清楚这一切。如果您需要更多帮助,请给我留言。
编辑:
我的问题和你的一样。我有一个 while(1) 循环,而我尝试过的其他事情需要互斥锁和其他花哨的多线程 mumbo jumbo,这增加了复杂性,调试是一场噩梦。除了简化代码之外,使用管道使我摆脱了这些复杂性。我并不是说它是最好的选择,但在我的情况下,它被证明是最好和最干净的选择。在这个解决方案之前,我被挂起的应用程序窃听了。