首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Qt6多线程问题

Qt6多线程问题
EN

Stack Overflow用户
提问于 2021-12-18 19:16:34
回答 1查看 212关注 0票数 1

我在读医生。但是我对多线程还不熟悉,我不能完全理解这些话题。

QT6.2.0在Ubuntu20.04下。基本上我有这样的功能:

代码语言:javascript
复制
bool Flow::checkNfc()
{
    QByteArray id;
    QByteArray data;

    bool ret = _nfc.read(&id, &data, 8);
    if (ret)
    {
        // do something
    }

    return ret;
}

它试图读取NFC标记,如果它找到它,就执行一些操作。这一职能:

代码语言:javascript
复制
bool ret = _nfc.read(&id, &data, 8);

调用一些阻止当前线程的libnfc函数。我只需要在另一个线程中执行这个函数,以避免应用程序的“口吃”。

因为checkNfc_nfc.read函数都需要与主线程交换数据,所以我不确定是否可以使用QFutureWatcher方法。我试过这样的方法:

代码语言:javascript
复制
QFutureWatcher<bool> watcher;
QFuture<bool> future = QtConcurrent::run(&MyProject::checkNfc);
watcher.setFuture(bool);

但是它返回的编译错误列表太长了,我想这是一种非常错误的方法。所以我想试试QThread解决方案。问题是,对于实际情况,示例太简单了:

代码语言:javascript
复制
class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const QString &parameter) {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }

signals:
    void resultReady(const QString &result);
};

不管怎样,我试过了,在我的主修课上,我写道:

代码语言:javascript
复制
private:
    QThread _nfcThread;
    MyNfc _nfc;

private slots:
    void nfc_readResult(bool success, QByteArray id, QByteArray data);

在构造函数中:

代码语言:javascript
复制
_nfc.moveToThread(&_nfcThread);
connect(&_nfcThread, &QThread::finished, &_nfc, &QObject::deleteLater);
connect(&_nfc, &MyNfc::resultRead, this, &MyProject::nfc_readResult);
_nfcThread.start();

从计时器插槽:

代码语言:javascript
复制
_nfc.doWork();

在MyNfc中:

代码语言:javascript
复制
signals:
    void resultRead(bool result, QByteArray id, QByteArray data);

public slots:
    void doWork();

以及:

代码语言:javascript
复制
void MyNfc::doWork()
{
    QByteArray id;
    QByteArray data;

    bool ret = read(&id, &data, 8);
    emit resultRead(ret, id, data);
}

一切都还在工作..。但是每次调用doWork()时,我的主应用程序仍然会阻塞。

我遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-18 19:24:30

您不能从主线程直接调用doWork(),因为在这种情况下,它将在主线程中调用,然后会被阻塞。就像你现在观察到的那样。

因此,触发工作人员在辅助线程中完成工作的正确方法是以下连接:

代码语言:javascript
复制
connect(&_nfcThread, &QThread::started, &_nfc, &MyNfc::doWork);

然后,您只需要启动线程,当线程启动时,它将调用doWork()

但是,代码中有更多的错误。您不应该连接到deleteLater(),因为您的线程是主类的成员,当主类被销毁时将被删除。如果在此之前调用deleteLater(),您将得到双重删除,这是未定义的行为。

因此,代码的重要部分应该是:

代码语言:javascript
复制
_nfc.moveToThread(&_nfcThread);
connect(&_nfcThread, &QThread::started, &_nfc, &MyNfc::doWork); // this starts the worker
connect(&_nfc, &MyNfc::resultRead, this, &MyProject::nfc_readResult); // this passes the result
connect(&_nfc, &MyNfc::resultRead, &_nfcThread, &QThread::quit); // this will quit the event loop in the thread
_nfcThread.start();

更新:如果您想定期调用插槽,请连接到计时器。工作完成后,不要退出线程。最简单的情况是:

代码语言:javascript
复制
_nfc.moveToThread(&_nfcThread);
connect(&_nfcThread, &QThread::started, &_timer, &QTimer::start); // this starts the timer after the thread is ready
connect(&_timer, &QTimer::timeout, &_nfc, &MyNfc::doWork); // start work at timer ticks
connect(&_nfc, &MyNfc::resultRead, this, &MyProject::nfc_readResult); // this passes the result
_nfcThread.start();

但是,由于您没有退出事件循环,所以需要在删除线程之前手动退出它。最好的地方是在主类的析构函数中。

代码语言:javascript
复制
MainClass::~MainClass()
{
  _nfcThread.quit(); // this schedules quitting of the event loop when the thread gets its current work done
  _nfcThread.wait(); // this waits for it, this is important! you cannot delete a thread while it is working on something.
  // ... because the thread (and the worker too) will get deleted immediately once this destructor body finishes, which is... right now!
}

但是,请注意,使用此解决方案时,您必须确保计时器的运行速度比处理数据所需的速度慢。否则,您将填充一个处理请求的队列,这些请求将等待很长时间才被处理,并且不会让线程完成,直到所有这些请求都满足为止。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70406357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档