这是基于白皮书“QThreads:你没有这么做错”中表达的想法使用子类QThread。它没有事件循环,也没有插槽。它只是发出信号并停止。实际上它的主要信号是QThread finished
。
基本上我有一个Qt使用后台线程来监控东西。在找到它要查找的内容后,它会记录其数据并终止。
终止向应用程序的主事件循环部分发送信号,该部分处理它,并在完成后重新启动背景。我通常可以让这个工作几十秒,但它似乎就好了。
似乎当主应用程序尝试启动该线程时,它并没有真正运行。我将此基于遥测代码,该代码在程序执行时递增计数器。
基本上
//in main application. Setup not shown.
//background points to the QThread sub-class object
void MainWindow::StartBackground()
{
background->startcount++;
background->start();
if ( background->isRunning() )
{
background->startedcount++;
}
}
//in sub-classed QThread
void Background::run()
{
runcount++;
//Do stuff until done
}
因此,当我注意到我的后台线程似乎没有运行时,通过观察Process Explorer,我导致调试器中断,并检查计数。我看到的是startcount
和startedcount
是平等的。并且值大于runcount
所以我只能得出结论说线程没有真正运行,但我无法找到任何证据证明原因。
我无法找到关于QThreads的文档,没有开始做某些错误条件,或者有什么证据表明存在这样的错误。
我想我可以设置一个插槽来捕获线程中的started
。启动代码可以在超时信号量上循环,一次又一次地尝试,直到started
插槽实际重置信号量。但它感觉很难看。
编辑 - 更多信息
因此,使用信号量方法,我有办法在无法启动时断点。
我想在isFinished()
之前就对start()
进行了抽样,这是假的。在我的100ms信号量超时后,它变成了现实。
所以这个问题似乎正演变成'为什么QThread有时会在finished()
变为真之前发出isFinished()
信号?
了解种族情况。我不想在开始下一个后台线程之前转动isFinished()
。
所以这可能是
的副本QThread emits finished() signal but isRunning() returns true and isFinished() returns false
但不完全是,因为我覆盖run()
并且我没有事件循环。
特别是该答案中的事件8和9的顺序不同。我的广告位在finished()
成立之前获得isFinished()
。
我不确定明确quit()
与让run()
返回有什么不同;
答案 0 :(得分:0)
听起来好像你有一个竞争条件,你可能会在上一次迭代实际完成之前尝试重新启动你的线程。如果是这样的话,那么从我看到的情况来看,对QThread::start
的下一次调用将被默默地忽略。您需要更新代码,以便在重新启动之前检查线程的状态 - 通过调用QThread::isFinished
或处理QThread::finished
信号。
另一方面......为什么线程反复启动/停止。简单地启动一次线程会不容易?无论在QThread::run
的上下文中运行什么代码,都可以监视它监视的内容,并在发现任何注意事项时发出主应用程序的信号。
更好。 Separate the monitor logic from the thread entirely...
class monitor: public QObject {
.
.
.
};
QThread monitor_thread;
monitor monitor;
/*
* Fix up any signals to/from monitor.
*/
monitor.moveToThread(&monitor_thread);
monitor_thread.start();
monitor
课程可以做任何想做的事情,当退出应用程序时,只需拨打monitor_thread::quit
。
答案 1 :(得分:0)
我正在使用的Qt版本中存在竞争条件。我以前不知道是否有报道,但我没有最新版本,所以除非我能在当前版本中展示它,否则它可能没有实际意义。
很久以前就报道了类似的错误:
QThread.isFinished returns False in slot connected to finished() signal
(我使用的版本比Qt 4.8.5更新)
更重要的是我可以使用以下代码解决它
while ( isRunning() )
{
msleep(1);
}
start();
我已经进行了一些测试,并且似乎从未花费超过1毫秒的竞争条件来解决。可能只需要一个上下文切换来清理。