當使用者點擊按鈕觸發耗時操作(如網路請求、大量運算)時,若直接在主執行緒執行,介面會凍結無響應。此時必須將耗時任務移至子執行緒,保持主執行緒(UI 執行緒)流暢。
網路上流傳的一種「移動對象到執行緒」寫法如下:
QThread pingThread; QObject::connect(&obj, SIGNAL(sig()), this, SLOT(getData()), Qt::QueuedConnection); Dummy dummy; obj.moveToThread(&pingThread); QObject::connect(&dummy, SIGNAL(sig()), &obj, SLOT(pingIp()), Qt::QueuedConnection); pingThread.start(); dummy.emitsig();
這段碼看似可行,實則隱藏嚴重隱患:
pingThread 是區域變數,函式結束時會被析構,但子執行緒可能仍在運行,導致程式崩潰。Qt::AutoConnection 在跨執行緒時行為不確定,必須顯式使用 Qt::QueuedConnection。// 標頭檔中宣告為成員 QThread *workerThread; WorkerObject *workerObj; // 建構時初始化 workerThread = new QThread(this); workerObj = new WorkerObject(); workerObj->moveToThread(workerThread); // 連線:工作完成發訊號回主執行緒 connect(workerObj, &WorkerObject::finished, this, &MainClass::onWorkFinished, Qt::QueuedConnection); // 啟動執行緒 workerThread->start(); // 觸發工作 QMetaObject::invokeMethod(workerObj, "doWork", Qt::QueuedConnection);
| 連線類型 | 行為 | 適用場景 |
|---|---|---|
Qt::DirectConnection | 立即同步呼叫槽函式 | 同一執行緒、需即時回應 |
Qt::QueuedConnection | 將槽呼叫放入接收方執行緒事件佇列 | 跨執行緒通訊首選 |
Qt::BlockingQueuedConnection | 同步阻塞等待槽執行完畢 | 需等待結果的跨執行緒呼叫 |
Qt::AutoConnection | 自動判斷(同執行緒 Direct,跨執行緒 Queued) | 一般情況,但跨執行緒建議顯式指定 |
new 並指定 parent。Qt::QueuedConnection,確保線程安全。本文轉載自 “賣萌程式設計師” 博客,原文出處:https://7677869.blog.51cto.com/7667869/1288018