Kan*_*oge 5 c++ qt qthread qt5 qtcore
我在使用Qt Threads和Connections时遇到了麻烦.我找到了关于这个主题的几个教程和讨论,我按照本教程创建了线程.但是我仍然遇到了问题,在线程上调用wait()永远不会返回并且UI冻结.
之前有一个类似的问题(第二个例子): 线程之间的Qt连接类型:为什么这有效?
在该问题的最后一次编辑中,作者提到他已经造成了僵局.我假设,我在我的应用程序中也这样做.但我仍然不明白,为什么会这样.阅读建议的文章并没有帮助我理解.我只是明白了,死锁可能发生,但我不知道,是什么导致它或在我的情况下.
我还创建了一个简化为核心问题的例子.找到这个问题底部的代码.
所以我的问题是:我的例子中死锁的原因是什么?是否有解决方案而不使连接成为直接连接?
我真的很感激任何提示.
谢谢!
编辑:
由于注释我试图通过信号发送停止请求,我在线程循环中添加了一个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();
}
Run Code Online (Sandbox Code Playgroud)
这实际上有效,工人自己控制如何停止工作.
提出这个问题之后,我也对冻结问题有一个解释:调用等待似乎使主线程保持繁忙或暂停,因此它不会处理任何事件.由于线程对象存在于主线程中,因此线程的finished()信号被输入但从未被处理过.
我的隐含假设,即thread.wait()仍然会使事件循环保持工作,这显然是错误的.但是,QThread :: wait()函数对于什么有用?!?
这只是一个理论,但也许这里有人可以验证或伪造它......
编辑3(最终解决方案):
在阅读了这篇小文章并阐述了一个子类化解决方案后,我认为这对于这个特定问题更为可取.不需要事件循环,我可以直接调用不同的线程并使用互斥保护.代码更少,更易于理解,更易于调试.
我想我只会使用非子类化策略,如果与线程的交互多于开始和暂停.
我减少了例子
也许我应该指出,我不删除线程,因为在我的原始应用程序中,我想稍后恢复,所以停止它实际上意味着暂停它.
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
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
主程序:
#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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1602 次 |
| 最近记录: |