解決QTimer報“Timers cannot be started from another thread“錯誤

? ? 今天在Qt編程時,將QTimer在子線程里執行start()函數,遇到“Timers cannot be started from another thread”問題,使用了如下AI工具,進行查詢:
? ? 提示詞A:“C++ QTimer 如何跨線程”
? ? 提示詞B:“C++ QTimer QThread::run 執行”
? ? 提示詞C:“C++ QThread::run 在start()之后 會自動退出嗎”

問題原因:QTimer本身不支持跨線程調用
解決方法:QTimer的運行,需要它所在的線程支持事件循環,若沒有事件循環,則調用QTimer::start()語句時,會報"Timers cannot be started from another thread"錯誤,即QTimer失效。
? ? 所以,要想讓QTimer在子線程里正常運行,則需要把該子線程的事件循環開啟即可。

注意:

  • 若QThread::run()沒有被重寫override,則默認是開啟了事件循環。
  • Qt的主線程,也默認開啟了事件循環;
  • C++ std::thread默認沒有事件循環;

1 米塔AI的回答

密塔AI官網: https://metaso.cn/

1.1 在QThread::run()函數里執行QTimer

? ? 在子線程中創建和使用QTimer:確保QTimer對象在子線程中創建,并且其信號和槽函數也在子線程中處理。
? ? // 代碼: codeA

   void WorkerThread::run(){QTimer timer;connect(&timer, &QTimer::timeout, this, &WorkerThread::onTimerTick);timer.start(1000); // 每秒觸發一次 timeout 信號exec(); // 啟動事件循環}

? ? codeA的含義是,在QThread::run()里創建一個QTimer對象,然后,也在run()里執行這個QTimer,
并通過exec()啟動事件循環。

1.2 將QTimer對象移動到子線程

? ? 創建一個繼承自QObject的類,比如Worker類,并在其中創建QTimer對象,然后將該對象移動到子線程中執行。例如:

? ? // 代碼: codeB

   class Worker : public QObject{Q_OBJECTprivate slots:void onTimeout(){qDebug() << "Worker::onTimeout get called from?: " << QThread::currentThreadId();}};int main(int argc, char *argv[]){QApplication a(argc, argv);qDebug() << "From main thread: " << QThread::currentThreadId();QThread t;QTimer timer;Worker worker;QObject::connect(&timer, &QTimer::timeout, &worker, &Worker::onTimeout);timer.start(1000);worker.moveToThread(&t);t.start();return a.exec();}

1.3 米塔AI的總結

? ? codeA和codeB,都是把QTimer的執行環境,放到子線程里,

  • 方法A: 通過在QThread::run()里,新建QTimer對象,讓QTimer的執行環境處于子線程中,并在子線程里啟動事件循環;
  • 方法B: 通過moveThread()函數,把QTimer的執行環境,從主線程移動到子線程;
    然后,再調用QTimer::start()函數,即可運行定時器,從而解決"Timers cannot be started from another thread"問題

2 DeepSeek的回答

? ? DeepSeek官網: https://chat.deepseek.com/
? ? 其他版本的DeepSeek,比如超算中心DeepSeek網站: https://chat.scnet.cn/#/home

2.1 在QThread::run()函數里執行QTimer

? ? 在 C++ 中使用 QTimer 和 QThread 時,如果想在 QThread::run() 中執行 QTimer,則需要注意的是QTimer 依賴于事件循環。

  • 若QThread::run()被重寫override,則需要手動提供事件循環QEventLoop ,即在run()函數里要加上exec()或者loop.exec()語句。
  • 若QThread::run()沒有被重寫override,則不需要手動提供事件循環QEventLoop 。

? ? 以下是一個示例,展示如何在 QThread::run() 中執行 QTimer:

#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include <QEventLoop>class WorkerThread : public QThread
{Q_OBJECTprotected:void run() override{qDebug() << "WorkerThread started in thread:" << QThread::currentThreadId();// 創建一個 QTimerQTimer timer;connect(&timer, &QTimer::timeout, this, &WorkerThread::onTimeout);// 啟動定時器,每隔 1 秒觸發一次timer.start(1000);// 創建一個事件循環以保持線程運行QEventLoop loop;connect(this, &WorkerThread::finished, &loop, &QEventLoop::quit); // 線程結束時退出事件循環loop.exec(); // 進入事件循環qDebug() << "WorkerThread finished.";}private slots:void onTimeout(){qDebug() << "Timeout occurred in thread:" << QThread::currentThreadId();}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);WorkerThread workerThread;qDebug() << "Main thread:" << QThread::currentThreadId();// 啟動工作線程workerThread.start();// 5 秒后停止工作線程QTimer::singleShot(5000, [&workerThread]() {qDebug() << "Stopping worker thread...";workerThread.quit(); // 退出線程的事件循環workerThread.wait();  // 等待線程結束qDebug() << "Worker thread stopped.";QCoreApplication::quit(); // 退出主事件循環});return a.exec();
}

2.2 將QTimer對象移動到子線程

? ? 通常,QTimer 在主線程中創建,但可以通過信號和槽機制在另一個線程中控制它。

  • a) 在主線程中創建 QTimer;
  • b) 將 QTimer通過moveThread()函數,移動到目標線程(也稱子線程);
  • c) 使用信號和槽進行跨線程通信;
    示例代碼如下:
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>class Worker : public QObject
{Q_OBJECTpublic:Worker(QObject *parent = nullptr) : QObject(parent){m_timer = new QTimer(this);connect(m_timer, &QTimer::timeout, this, &Worker::onTimeout);}void startTimer(){m_timer->start(1000); // 1秒觸發一次}void stopTimer(){m_timer->stop();}public slots:void onTimeout(){qDebug() << "Timeout occurred in thread:" << QThread::currentThreadId();}private:QTimer *m_timer;
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QThread workerThread;Worker worker;// 將 worker 移動到 workerThreadworker.moveToThread(&workerThread);// 啟動線程workerThread.start();// 使用信號和槽啟動定時器QTimer::singleShot(0, &worker, &Worker::startTimer);// 5秒后停止定時器并退出線程QTimer::singleShot(5000, [&]() {worker.stopTimer();workerThread.quit();workerThread.wait();qDebug() << "Timer stopped, thread finished.";a.quit();});return a.exec();
}

關鍵點

  1. moveToThread: 將 Worker 對象移動到新線程,確保 QTimer 在新線程的事件循環中運行。
  2. 信號和槽: 使用 QTimer::singleShot 和信號槽機制跨線程控制 QTimer。
  3. 線程安全: QTimer 的操作是線程安全的,前提是它在其所在線程的事件循環中運行。
  4. 通過 moveToThread 和信號槽機制,可以安全地在多線程環境中使用 QTimer,確保定時器在正確的線程中運行。

3 豆包AI的回答

? ? 豆包AI,既有客戶端版本,也有網頁版本,這里給出的是網頁版本的豆包AI地址:
https://www.doubao.com/chat/?channel=browser_landing_page

3.1 在QThread::run()函數里執行QTimer

? ? 在Thread::run()函數里,新建一個QTimer對象,然后,調用QTimer::start(),再啟動事件循環exec()。

#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>// 自定義線程類
class MyThread : public QThread {Q_OBJECT
public:explicit MyThread(QObject *parent = nullptr) : QThread(parent) {}protected:void run() override {QTimer timer;timer.setInterval(1000); // 設置定時器間隔為1秒connect(&timer, &QTimer::timeout, []() {qDebug() << "Timer timeout in thread:" << QThread::currentThreadId();});timer.start();exec(); // 啟動線程的事件循環}
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);MyThread thread;thread.start();return a.exec();
}#include "main.moc"

3.2 將業務對象(非QTimer)通過moveThread()移動到子線程,

? ? 豆包AI的回答,比前面2個AI: 密塔AI、DeepSeek的回答,更加簡簡潔。
? ? 它是將純業務對象Worker移動到子線程,而QTimer仍在主線程,QTimer通過信號槽機制,與業務對象Worker關聯起來。

  • 將線程QThread的啟動信號start,綁定到QTimer的start()槽函數;
  • 同時,QTimer的超時信號timeout,綁定Worker的handleTimeout()槽函數;

? ? 這種方式,間接的實現了跨線程調用QTimer。
? ? 即子線程thread --> 主線程的timer;

#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>// 自定義工作類
class Worker : public QObject {Q_OBJECT
public:explicit Worker(QObject *parent = nullptr) : QObject(parent) {}public slots:void handleTimeout() {qDebug() << "Timer timeout in thread:" << QThread::currentThreadId();}
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 創建工作對象和線程Worker worker;QThread thread;worker.moveToThread(&thread);// 創建定時器QTimer timer;timer.setInterval(1000); // 設置定時器間隔為1秒// 連接信號和槽QObject::connect(&timer, &QTimer::timeout, &worker, &Worker::handleTimeout);QObject::connect(&thread, &QThread::started, &timer, QOverload<>::of(&QTimer::start));// 啟動線程thread.start();return a.exec();
}

4 QTimer跨線程調用的總結

方式直接調用QTimer間隔調用QTimer
A在QThread::run()函數里創建QTimer,并運行QTimer,啟動事件循環將QTimer對象移動到子線程
B在QThread::run()函數里執行QTimer,并運行QTimer,啟動事件循環將業務對象Woker到子線程,然后QTimer的超時信號綁定Worker里的槽函數

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/895241.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/895241.shtml
英文地址,請注明出處:http://en.pswp.cn/news/895241.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【AI知識點】苦澀的教訓 The Bitter Lesson by Rich Sutton(2019)

【AI論文解讀】【AI知識點】【AI小項目】【AI戰略思考】【AI日記】【讀書與思考】【AI應用】 “The Bitter Lesson” 是由 Richard Sutton&#xff08;強化學習領域的先驅之一&#xff09;提出的一個概念&#xff0c;指的是機器學習領域在長期發展過程中&#xff0c;尤其是在強…

單片機上SPI和IIC的區別

SPI&#xff08;Serial Peripheral Interface&#xff09;和IC&#xff08;Inter-Integrated Circuit&#xff09;是兩種常用的嵌入式外設通信協議&#xff0c;它們各有優缺點&#xff0c;適用于不同的場景。以下是它們的詳細對比&#xff1a; — 1. 基本概念 SPI&#xff0…

SQL Server安裝流程

SQL Server 2022在安全性、可用性和性能方面不斷創新&#xff0c;是現在最支持Azure的SQL Server版本。 SQL Server發展史 SQL Server的歷史始于1989年&#xff0c;當時是由微軟與Sybase合作的產品&#xff0c;旨在為Windows NT操作系統提供一個高性能的數據庫解決方案。隨著…

VSOMEIP ROUTING應用和CLIENT應用之間交互的消息

#define VSOMEIP_ASSIGN_CLIENT 0x00 // client應用請求分配client_id #define VSOMEIP_ASSIGN_CLIENT_ACK 0x01 // routing應用返回分配的client_id #define VSOMEIP_REGISTER_APPLICATION 0x02 // client應用注冊someip應用 #…

jvm 線程監控調試

文章目錄 前言一、使用JDK工具轉儲線程文件(如jstack)1. 找到Java進程的PID:2. 使用jstack生成線程轉儲文件:3.驗證生成的線程轉儲文件:二、分析文件1.使用在線工具進行分析上傳thread-dump文件,等待解析完成2.查看分析結果總結前言 提示:使用jdk自帶工具轉儲線程監控文…

從零開始認識大語言模型(LLM)

“AI小美好——聚焦科技、商業、職場。前沿資訊&#xff0c;實用干貨&#xff0c;邂逅更美好的自己&#xff01;” 在當今數字化時代&#xff0c;語言不僅是人類交流的工具&#xff0c;更是信息傳遞的核心。隨著人工智能技術的飛速發展&#xff0c;大語言模型逐漸走進了我們的…

安裝OpenJDK21(linux、macos)

文章目錄 安裝OpenJDK21java21linux下安裝配置mac下安裝 安裝OpenJDK21 java21 封神&#xff01;Java 21正式發布了&#xff0c;迎來了史詩級新特性&#xff0c;堪稱版本最強&#xff01;&#xff01;&#xff01; 視頻鏈接&#xff1a;https://www.bilibili.com/video/BV1E8…

idea插件開發,如何獲取idea設置的系統語言

手打不易&#xff0c;如果轉摘&#xff0c;請注明出處&#xff01; 注明原文&#xff1a;https://zhangxiaofan.blog.csdn.net/article/details/145578160 版本要求 大于 2024.3 錯誤用法 網上有的說使用&#xff1a;UIUtil com.intellij.util.ui.UIUtil 代碼示例&#xf…

Linux | 系統調用

文章目錄 Linux | 系統調用open 系統調用功能頭文件和函數原型參數解釋返回值示例代碼 其他常用系統調用read 系統調用write 系統調用close 系統調用lseek 系統調用stat 系統調用 Linux | 系統調用 前言&#xff1a;在Linux系統中&#xff0c;系統調用是用戶空間程序與內核進行…

郭羽沖IOI2024參賽總結

非常榮幸能代表中國參加第 36 36 36 屆國際信息學奧林匹克競賽&#xff08; I O I 2024 IOI2024 IOI2024&#xff09;。感謝 C C F CCF CCF 為我們提供競賽的平臺&#xff0c;感謝隨行的老師們一路上為我們提供的幫助與支持。 在每場比賽的前一個晚上&#xff0c;領隊、副領…

基于Java的自助多張圖片合成拼接實戰

目錄 前言 一、圖片合成需求描述 二、圖片合成設計與實現 1、編程語言 2、基礎數據準備 3、圖片合成流程 4、圖片合成實現 三、總結 前言 在當今數字化時代&#xff0c;圖像處理技術在各個領域都發揮著至關重要的作用。從社交媒體到電子商務&#xff0c;從在線教育到虛擬…

計算機網絡結課設計:通過思科Cisco進行中小型校園網搭建

上學期計算機網絡課程的結課設計是使用思科模擬器搭建一個中小型校園網&#xff0c;當時花了幾天時間查閱相關博客總算是做出來了&#xff0c;在驗收后一直沒管&#xff0c;在寒假想起來了簡單分享一下&#xff0c;希望可以給有需求的小伙伴一些幫助 目錄 一、設計要求 二、…

在npm上傳屬于自己的包

最近在整理代碼&#xff0c;上傳到npm方便使用&#xff0c;所以學習了如何在npm發布一個包&#xff0c;整理寫成一篇文章和大家一起交流。 1、注冊npm賬號 npm | Home 2、確保是登錄狀態 &#xff08;在包目錄下&#xff0c;終端執行 npm login) 按enter鍵自動打開頁面&…

物聯網(IoT)詳解

物聯網&#xff08;IoT&#xff09;詳解 1. IoT定義簡介2. IoT工作原理3. IoT關鍵技術4. 物聯網與互聯網區別5. IoT使用場景6. 開源物聯網平臺7. 參考資料 1. IoT定義簡介 首先第一個問題&#xff0c;什么是物聯網&#xff08;IoT&#xff09;? 物聯網&#xff08;英文&#…

【人工智能】解碼語言之謎:使用Python構建神經機器翻譯系統

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 神經機器翻譯(NMT)是近年來機器翻譯領域的一項重大突破。它利用深度學習模型,特別是循環神經網絡(RNN)和Transformer網絡,以端到端的…

idea項目列表不出現,展示loading

2025年02月08 11:23:36 星期六 發生在webstorm中&#xff0c;跟其他idea類似 原因是將 ignore 插件升級到 4.5.5 版本 https://github.com/JetBrains/idea-gitignore/pull/933 解決方案&#xff1a;將ignore版本將為 4.5.4 我是將 4.5.5 降低為 4.5.4 正常顯示文件夾了。

DeepSeek本地部署詳細指南

DeepSeek本地部署詳細指南 隨著人工智能技術的飛速發展&#xff0c;本地部署大模型的需求也日益增加。DeepSeek作為一款開源且性能強大的大語言模型&#xff0c;提供了靈活的本地部署方案&#xff0c;讓用戶能夠在本地環境中高效運行模型&#xff0c;同時保護數據隱私。以下是…

算法隨筆_46: 最長公共前綴

上一篇:算法隨筆_45: 車隊-CSDN博客 題目描述如下: 編寫一個函數來查找字符串數組中的最長公共前綴。 如果不存在公共前綴&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 輸入&#xff1a;strs ["flower","flow","flight"] 輸…

learn torch 01

pytorch學習 在安裝完conda時&#xff0c;需要在windows上修改pip配置路徑具體操作如下 文件管理器文件路徑地址欄敲:%APPDATA%回車&#xff0c;快速進入C:\Users\電腦用戶\AppData\Roaming文件夾中 新建pip文件夾并在文件夾中新建pip.ini配置文件 需要在pip.ini配置文件內容&a…

【Vue】在Vue3中使用Echarts的示例 兩種方法

文章目錄 方法一template渲染部分js部分方法一實現效果 方法二template部分js or ts部分方法二實現效果 貼個地址~ Apache ECharts官網地址 Apache ECharts示例地址 官網有的時候示例顯示不出來&#xff0c;屬于正常現象&#xff0c;多進幾次就行 開始使用前&#xff0c;記得先…