2015-11-15 45 views
0

这是主要部分。主线程无法获得信号形式工作线程

此代码创建一个工作者和一个工作线程。

工人被转移到工作地点。

工人正在等待信号让它工作。

工作完成后,工作人员发出信号并显示结果。

主要应该捕获该信号并初始化主变量。

main() 
{......... 
// This is the variable to be changed 
variableToGetFromWorker = 0; 

qDebug() << "Main thread: " << QThread::currentThreadId(); 

QThread workerThread; 
worker* stupidTom = new stupidTom(number); 

worker->moveToThread(&workerThread); 
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater); 
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob())); 
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int))); 

workerThread.start(); 
workerThread.wait(); 
...........} 


// This is a slot at main. Suppose to catch the signal from the worker 

void main::jobDone(int result) 
{ 
    qDebug() << "Changing variable"; 
    variableToGetFromWorker = result; 
} 

这是工人的doJob插槽。

void worker::doJob() 
{ 
    qDebug() << "worker::doJob invoked."; 
    qDebug() << "worker Thread:" << QThread::currentThreadId(); 

    // Doing Job here 

    emit jobDone(result); 
} 

这是qDebug导致

Main thread: 0x7ffff7fc6780 
worker::doJob invoked. 
worker Thread: 0x7fffdab44700 

在调试模式下,我发现程序是停在workerThread.wait() ,从来没有去main::jobDone(int result)。是什么原因?在主码

小编辑:

QThread workerThread; 
worker* stupidTom = new stupidTom(number); 

worker->moveToThread(&workerThread); 
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater); 
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob())); 
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int))); 
connect(stupidTom, SIGNAL(jobDone(int)), &workerThread, SLOT(quit())); 

workerThread.start(); 
workerThread.wait(); 

回答

2

只要信号应该调用时隙。对于应该运行插槽或特定jobDone信号的主线程,这不适用于wait()

请确保了解您的应用程序中QThread::exec()QThread::wait()之间的差异。通常在真正的应用程序中,线程会循环(运行),而启动它的线程仍然循环。该循环在受保护的QThread::exec()方法中实施。我们通常不需要明确地调用exec(),但我们需要允许线程运行。你可以通过使主要功能使用QEventLoop的循环:

int main() 
{ 
//... 
    workerThread.start(); 
    QEventLoop eventLoop; 
// here you will probably want to hook-up QEventLoop::quit() slot 
// to eventually quit the process 
    int returnCode = eventLoop.exec(); 
//... 
    return returnCode; 
} 

,这也是错误的:

connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob())); 

相反,你应该创建自己的工作对象,并为它做QObject::moveToThread。这里有一个很好的article。所以它应该看起来像:

connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob())); 

我可能明白你为什么试图像上面那样运行线程。它与许多C++示例类似。你也可以在Qt中做到这一点,但你也需要意识到完成workerThread的过程。而Qt最流行的做线程间交互的方式是信号和插槽。这就是为什么我们应该在main中使用QEventLoop。但当然有另一种选择。对于较低级别的普通C++,您可以使用互斥锁和条件变量来完成相同的操作。或者相同的wait(),但是没有涉及任何信号。

还要观察调试输出,不管所有连接语句是否真正将正确的信号连接到插槽。如果没有连接,则打印警告。

+0

我不明白添加eventloop的原因。首先,我很抱歉有一个错字。我正在使用你指出的connect(&workerThread,SIGNAL(start()),stupidTom,SLOT(doJob()));'。 worker对象是我创建的对象,仅用于传递给线程。 – tom

+0

参考你提到的文章,我增加了一个连接'connect(stupidTom,SIGNAL(jobDone(int)),&workerThread,SLOT(quit()));'。当'jobDone()'被释放时,它假设退出线程。没有连接警告。我知道'发射jobDone(result);'真的发射了。但是很确定'mainDown()'没有被调用,因为debug msg没有被打印。 – tom

+1

jobDone()不能被调用,因为跨线程信号需要接收线程中的事件循环才能运行。该事件循环也不能永久封锁,因为调用workerThread.wait()会执行。 –