我在读这和这医生。但是我对多线程还不熟悉,我不能完全理解这些话题。
QT6.2.0在Ubuntu20.04下。基本上我有这样的功能:
bool Flow::checkNfc()
{
QByteArray id;
QByteArray data;
bool ret = _nfc.read(&id, &data, 8);
if (ret)
{
// do something
}
return ret;
}它试图读取NFC标记,如果它找到它,就执行一些操作。这一职能:
bool ret = _nfc.read(&id, &data, 8);调用一些阻止当前线程的libnfc函数。我只需要在另一个线程中执行这个函数,以避免应用程序的“口吃”。
因为checkNfc和_nfc.read函数都需要与主线程交换数据,所以我不确定是否可以使用QFutureWatcher方法。我试过这样的方法:
QFutureWatcher<bool> watcher;
QFuture<bool> future = QtConcurrent::run(&MyProject::checkNfc);
watcher.setFuture(bool);但是它返回的编译错误列表太长了,我想这是一种非常错误的方法。所以我想试试QThread解决方案。问题是,对于实际情况,示例太简单了:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};不管怎样,我试过了,在我的主修课上,我写道:
private:
QThread _nfcThread;
MyNfc _nfc;
private slots:
void nfc_readResult(bool success, QByteArray id, QByteArray data);在构造函数中:
_nfc.moveToThread(&_nfcThread);
connect(&_nfcThread, &QThread::finished, &_nfc, &QObject::deleteLater);
connect(&_nfc, &MyNfc::resultRead, this, &MyProject::nfc_readResult);
_nfcThread.start();从计时器插槽:
_nfc.doWork();在MyNfc中:
signals:
void resultRead(bool result, QByteArray id, QByteArray data);
public slots:
void doWork();以及:
void MyNfc::doWork()
{
QByteArray id;
QByteArray data;
bool ret = read(&id, &data, 8);
emit resultRead(ret, id, data);
}一切都还在工作..。但是每次调用doWork()时,我的主应用程序仍然会阻塞。
我遗漏了什么?
发布于 2021-12-18 19:24:30
您不能从主线程直接调用doWork(),因为在这种情况下,它将在主线程中调用,然后会被阻塞。就像你现在观察到的那样。
因此,触发工作人员在辅助线程中完成工作的正确方法是以下连接:
connect(&_nfcThread, &QThread::started, &_nfc, &MyNfc::doWork);然后,您只需要启动线程,当线程启动时,它将调用doWork()。
但是,代码中有更多的错误。您不应该连接到deleteLater(),因为您的线程是主类的成员,当主类被销毁时将被删除。如果在此之前调用deleteLater(),您将得到双重删除,这是未定义的行为。
因此,代码的重要部分应该是:
_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();更新:如果您想定期调用插槽,请连接到计时器。工作完成后,不要退出线程。最简单的情况是:
_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();但是,由于您没有退出事件循环,所以需要在删除线程之前手动退出它。最好的地方是在主类的析构函数中。
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!
}但是,请注意,使用此解决方案时,您必须确保计时器的运行速度比处理数据所需的速度慢。否则,您将填充一个处理请求的队列,这些请求将等待很长时间才被处理,并且不会让线程完成,直到所有这些请求都满足为止。
https://stackoverflow.com/questions/70406357
复制相似问题