2011-04-26 40 views
2

我想在线程完成运行时通知对象。但是,我无法让线程正常退出。我有以下代码:QThread - 使用插槽quit()退出线程

Processor.cpp

thread = new QThread; 
tw = new ThreadWorker; 
connect(tw, SIGNAL(updateStatus(QString)), this, SLOT(statusUpdate(QString))); 
tw->doSetup(thread, strDic); 
tw->moveToThread(thread); 
thread->start(); 

while(thread->isRunning()) 
{ 
} 

qDebug() << "Thread Finished"; 

ThreadWorker.cpp

void ThreadWorker::doSetup(QThread *thread, const string &path) 
{ 
    _strPath = path; 
    connect(thread, SIGNAL(started()), this, SLOT(run())); 
    connect(this, SIGNAL(finished()), thread, SLOT(quit())); //tried terminate() also 
} 


void ThreadWorker::run() 
{ 
    DirectorySearch dicSearch; 
    vector<string> vecFileList = dicSearch.getFileList(_strPath); 
    emit updateStatus("Directory Fetched"); 
    emit finished(); 
} 

的退出()槽似乎并没有停止线程(的QThread :: isFinished从未返回true )。有人能指引我朝着正确的方向吗?

(注:ThreadWorker不从QThread的继承)

+2

只是为了测试...尝试在while循环中添加QCoreApplication :: instance() - > processEvents()。这只是一个建议,所以我不会将它作为答案发布。这可能是因为QThread本身位于主线程中,所以它的OWN槽可能在主事件循环中调用,而不是ThreadWorker的槽,它应该在QThread中执行。 – Raiv 2011-04-26 16:35:34

+0

@Raiv:spot-on,我认为 – 2011-04-26 17:09:08

回答

4

假设Processor.cpp正在您的主线程中运行,while(thread->isRunning())循环让您的主线程完全绑定。这意味着您的应用程序的事件循环无法进行任何处理,因此例如信号updateStatus()将永远不会得到处理。正如在评论中提到的那样,因为QThread对象是由主线程创建的,所以它的信号将不起作用,因为它们也会要求主事件循环做它的事情。此外,如果您正在主线程中等待您的工作线程执行某些操作,为什么要使用工作线程呢? :)

尝试取出while循环,增加槽workDone()(或任何你想将它命名),以Processor.cpp和连接到您的Threadworkerfinished()信号。

-1

而不是做你的“doSetup”功能......你moveToThread之前,在总重量上总重量的母公司边界处理和插槽之间建立连接。

我会做4个连接。 首先是ThreadWorker中的运行方法。这很简单,并且足够自我解释。

其次是从您的完成信号到下面的第三个SIGNAL连接。退出线程的信号

第三个应该调用该线程的terminate()插槽的信号。当你连接到run方法时,这将有效地关闭事件循环设置(当你执行start()时exec被自动调用)并且由于你的run方法不是某种类型的循环,将会关闭线程而不会出现问题。

Forth从线程的terminate()信号到tw的父节点中的SLOT。这会告诉你什么时候线程死了,如果你想在这一点上做点什么。

你做了上面的连接(如果你需要传递字符串,向run方法和相应的SIGNAL连接添加一个变量,你将获得数据),移动到线程,线程启动,然后执行SIGNAL附加到运行方法。让它做它的事情。当它完成时,它将完成一个完成信号,该信号被绑定到与线程终止时隙相关的另一个信号。这将杀死事件循环并退出线程,推出终止的信号,然后您可以执行某些操作。

+0

-1建议在正常操作中使用terminate()。 – 2011-04-26 13:46:32

+0

我提到的终止的唯一原因是因为它是通过一个最终在运行循环结束时发出的信号调用的。我在上面的回答中提到了这一点。通常情况下,你会想退出...但这种情况没有什么不同。 – g19fanatic 2011-04-26 14:21:49

+0

错了。槽的原始问题实际上并没有被调用:使用'quit()','ThreadWorker :: run()'可以自行清理。在控制返回到“ThreadWorked :: run()”之前,赛跑'terminate()'可能会终止线程,在这种情况下,例如本地对象的析构函数将不会被调用。 – 2011-04-26 14:29:07

3

我有同样的问题,并找到答案。这里是我的问题: What is the use of QThread.wait() function?

解决你的问题,你不需要运行QCoreApplication ::实例() - 在你的while循环> processEvents(),你需要做的是什么,而不是调用尝试将信号发送到创建线程的事件循环(现在被while循环阻止)的quit(),您必须直接调用它。

因此,对于你的代码,删除线:

connect(this, SIGNAL(finished()), thread, SLOT(quit())); //tried terminate() also 

,而不是和:

emit finished(); 

用途:

this->thread()->quit(); 

田田......问题就迎刃而解了。获得的经验:不要试图通过qt signal-slot机制退出工作线程,因为你的信号并不会到达它们所期望的位置(工作线程的事件循环),但它们最终会在创建线程代替。你永远不知道那个线程正在做什么,如果它的事件循环正在运行或者没有运行,并且这对你的工作线程来说不应该是事务性的,反而直接调用quit。

1

您可以使用Qt :: DirectConnection:

connect(this, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection); 

这将停止线程。