我在Qt线程和连接方面遇到了一些麻烦。我发现了几个关于这个主题的教程和讨论,我遵循this tutorial来创建线程。但我仍然遇到了这个问题:在线程上调用wait()将永远不会返回,并且UI会冻结。QThread :: wait()在不使用直接连接的情况下不会返回
类似的问题在这里问(第二个例子)前: Qt connection type between threads: why does this work?
在问题的最后编辑,作者提到,他已经创造了一个僵局。我假设,我在我的申请中也是这样做的。但我仍然不明白,为什么会发生这种情况。阅读suggested article并没有帮助我理解。我刚刚明白,僵局可能会发生,但我不知道,究竟是什么原因造成了这种情况,或者是我的情况。
我也创建了一个简化为核心问题的例子。在这个问题的底部找到代码。
所以我的问题是: 究竟是什么原因造成我的例子中的死锁? 有没有一种解决方案,但没有建立连接直接连接?
我真的很感激任何提示。
谢谢!
编辑:
因为意见的我试了一下通过信号发送的停止请求和我说的线环QCoreApplication :: processEvents()调用。但主要问题仍然是一样的。
EDIT2:
我发现了一个可接受的解决方案,想了多一点有关事件后循环:
thread.requestStop();
// now instead of using wait(), we poll and keep the event loop alive
// polling is not nice, but if it does not take a very long time
// for the thread to finish, it is acceptable for me.
while (thread.isRunning())
{
// This ensures that the finished() signal
// will be processed by the thread object
QCoreApplication::processEvents();
}
这实际工作和工人本身控制如何停止工作。
在提出这个问题后,我也对冻结问题做了一个解释:调用等待似乎使主线程忙或暂停,因此它不处理任何事件。由于线程对象存在于主线程中,所以线程的完成()信号被设置,但从未处理。
我隐含的假设,即thread.wait()仍然会保持事件循环的工作,显然是错误的。但是,那么QThread :: wait()函数有什么好处呢?!?
这只是一种理论,但也许这里有人能证实或证伪它...
编辑3(最终的解决方案):
阅读this small article和implmenting一个子类化的解决方案之后,我觉得这对于这个特定的问题是优选的。不需要事件循环,我可以直接调用另一个线程并使用互斥锁保护。它代码少,易于理解和调试。
我想我只会使用非子类化策略,如果与线程有更多的交互而不仅仅是启动和暂停。
我减少实例
也许我应该指出的是,我不删除线程,因为我原来的应用程序,我想以后恢复,所以停止它实际上意味着暂停它。
worker.h:
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject* parent = NULL);
public slots:
void doWork();
void requestStop();
signals:
void finished();
private:
bool stopRequested;
QMutex mutex;
};
#endif // WORKER_H
worker.cpp:
#include "worker.h"
#include <QThread>
#include <iostream>
using namespace std;
Worker::Worker(QObject *parent)
: stopRequested(false)
{
}
void Worker::doWork()
{
static int cnt = 0;
// local loop control variable
// to make the usage of the mutex easier.
bool stopRequesteLocal = false;
while (!stopRequesteLocal)
{
cout << ++cnt << endl;
QThread::msleep(100);
mutex.lock();
stopRequesteLocal = stopRequested;
mutex.unlock();
}
cout << "Finishing soon..." << endl;
QThread::sleep(2);
emit finished();
}
void Worker::requestStop()
{
mutex.lock();
stopRequested = true;
mutex.unlock();
}
主程序:
#include <QCoreApplication>
#include <QThread>
#include <QtCore>
#include <iostream>
#include "worker.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread thread;
Worker worker;
QObject::connect(&thread, SIGNAL(started()), &worker, SLOT(doWork()));
// this does not work:
QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()));
// this would work:
//QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()), Qt::DirectConnection);
// relocating the moveToThread call does not change anything.
worker.moveToThread(&thread);
thread.start();
QThread::sleep(2);
worker.requestStop();
cout << "Stop requested, wait for thread." << endl;
thread.wait();
cout << "Thread finished" << endl;
// I do not know if this is correct, but it does not really matter, because
// the program never gets here.
QCoreApplication::exit(0);
}
'sleep'是Qt中的一个保护,你怎么能调用QThread :: sleep(2);? – UmNyobe
我不知道。我只是这样做,它的工作。 ;) – Kanalpiroge
这是不可能的:)你是否编辑过Qt源代码? –