我在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源代碼? –