我正在閱讀這個和這個檔案。但是我對多執行緒還是個新手,我無法完全理解這些主題。
Ubuntu 20.04 下的 Qt 6.2.0。基本上我有這個功能:
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()。
我錯過了什么?
uj5u.com熱心網友回復:
您不能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://www.uj5u.com/qiye/385156.html
上一篇:是否有使用terraform的應用程式網關的Web重定向方法或示例?
下一篇:字串轉二進制
