gpt4 book ai didi

c++ - QThread::wait() 不使用直接连接不返回

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:35:01 26 4
gpt4 key购买 nike

我在使用 Qt 线程和连接时遇到了一些问题。我找到了几个关于这个主题的教程和讨论,我关注了this tutorial创建线程。但我仍然遇到问题,即在线程上调用 wait() 永远不会返回并且 UI 卡住。

之前在这里问过类似的问题(第二个例子): Qt connection type between threads: why does this work?

在问题的最后一次编辑中,作者提到他造成了僵局。我假设,我在我的应用程序中做同样的事情。但是我还是不明白,为什么会这样。阅读 suggested article没有帮助我理解。我只是明白了,死锁可能会发生,但我不知道是什么原因造成的,或者在我的情况下。

我还创建了一个简化为核心问题的示例。找到此问题底部的代码。

所以我的问题是:在我的示例中,死锁的确切原因是什么?有没有不用直接连接的解决方案?

如果有任何提示,我将不胜感激。

谢谢!

编辑:

由于评论,我尝试通过信号发送停止请求,并在线程循环中添加了 QCoreApplication::processEvents() 调用。但主要问题还是一样。

编辑 2:

在对事件循环进行更多思考后,我找到了一个可接受的解决方案:

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();
}

这确实有效,工作人员自己控制如何停止工作。

想到这个之后,对于卡顿的问题我也有了一个解释:调用wait好像是让主线程要么忙要么挂,所以它不处理任何事件。由于线程对象存在于主线程中,因此线程的 finished() 信号被排队但从未被处理。

我隐含的假设,即 thread.wait() 仍会保持事件循环工作,显然是错误的。但是,QThread::wait() 函数有什么用?!?

这只是一个理论,但也许这里有人可以验证或证伪它......

编辑 3(最终解决方案):

看完this small article并实现子类化解决方案,我认为这对于这个特定问题更可取。不需要事件循环,我可以在不同的线程上直接调用并使用互斥锁保护。它的代码更少,更易于理解和调试。

我认为我只会使用非子类化策略,如果与线程的交互不仅仅是启动和暂停的话。


我的简化示例

也许我应该指出,我没有删除线程,因为在我原来的应用程序中,我想稍后恢复,所以停止它实际上意味着暂停它。

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);
}

最佳答案

我将自己的答案作为 EDIT 3 添加到问题文本中。

关于c++ - QThread::wait() 不使用直接连接不返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20640068/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com