有5個方式:可以參考這個博客:Qt 中開啟線程的五種方式_qt 線程_lucky-billy的博客-CSDN博客
注:為了實現更加靈活的線程管理(因為這5種都有一些不方便之處:QThread需要子類化且不能傳參,moveToThread不能傳參且只能移入一個對象而不是一個函數,QThreadPool 需要子類化QRunnable且只能啟動一個對象,QtConcurrent支持傳參但是不能管理它,std::thread能夠傳入函數以及給定實參但是不是qt方式了),我自己實現了一個更好用的線程管理類(支持指定一個函數,同時指定傳入的實參,而且能管理該線程例如隨時終止等),看我這個博客:?qt自己實現方便的線程管理類_我是標同學的博客-CSDN博客
接下來,講解這5種方式情況:?
1. 繼承 QThread 重寫 run 函數
class Thread : public QThread
{
? ? Q_OBJECT
public:
?? ?virtual void run() override;
}
優點:構造使用方式簡單,所有操作都放在run()方法里面。而且可以隨時停止,因為這是以線程對象形式存在,我們可以對其進行各種管理。
缺點:不夠靈活,只能運行run()里面的程序。此外,傳入的函數不能同時給參數,只能另外一個函數設置其成員變量,run函數里讀取該成員變量。
2. 繼承 QObject 調用 moveToThread
QThread th;
Test test;
test.moveToThread(&th);
優點:使用簡單,可以使用信號槽通信,很靈活。
缺點:每次都要創建線程,帶來不必要資源開支。而且是整個對象給弄進去,也挺重的。
3. 繼承 QRunnable 重新 run 函數,結合 QThreadPool 實現線程池
我們使用線程的時候就去創建一個線程,這樣實現起來非常簡便,但是就會有一個問題:如果并發的線程數量很多,并且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,因為頻繁創建線程和銷毀線程需要時間。
還有一個問題需要注意一下,QThread 是集成自 QObject 的,我們通常會使用信號槽與外界進行通信。而 QRunnable 并不是繼承自 QObject 類的,所以他無法使用信號槽機制進行通信。這里推薦兩種方法,一個是使用 QMetaObject::invokeMethod()函數。另一個是使用多重繼承的方法,自定義類需要同時繼承自 QRunnable 和 QObject
每個Qt應用程序都有一個全局 QThreadPool 對象,可以通過調用 globalInstance() 來訪問它。==也可以單獨創建一個?QThreadPool?對象使用。
class BPrint : public QRunnable
{
?? ?void run()
?? ?{
?? ? ? ?for ( int count = 0; count < 5; ++count )
?? ? ? ?{
?? ??? ??? ?qDebug() << QThread::currentThread();
?? ??? ??? ?QThread::msleep(1000);
?? ? ? ?}
?? ?}
};
一般情況下,我們不需要在 Qt 程序中創建線程池對象,**直接使用 Qt 為每個應用程序提供的線程池全局對象即可。得到線程池對象之后,調用 start() 方法**就可以將一個任務添加到線程池中,這個任務就可以被線程池內部的線程池處理掉了,使用線程池比自己創建線程的這種多種多線程方式更加簡單和易于維護。
?
4. 使用 C++ 11 中的 std::thread
#include <thread>
void threadfun1()
{
? ? std::cout << "threadfun1 - 1\r\n" << std::endl;
? ? std::this_thread::sleep_for(std::chrono::seconds(1));
? ? std::cout << "threadfun1 - 2" << std::endl;
}
void threadfun2(int iParam, std::string sParam)
{
? ? std::cout << "threadfun2 - 1" << std::endl;
? ? std::this_thread::sleep_for(std::chrono::seconds(5));
? ? std::cout << "threadfun2 - 2" << std::endl;
}
int main()
{
? ? std::thread t1(threadfun1);
? ? std::thread t2(threadfun2, 10, "abc");
? ? t1.join();?? ??? ?// 等待線程 t1 執行完畢
? ? std::cout << "join" << std::endl;
? ? t2.detach();?? ?// 將線程 t2 與主線程分離
? ? std::cout << "detach" << std::endl;
}
t1.join() 會等待t1線程退出后才繼續往下執行,t2.detach() 并不會等待,detach字符輸出后,主函數退出,threadfun2還未執行完成,但是在主線程退出后,t2的線程也被已經被強退出
5. Qt QtConcurrent 之 Run 函數
簡單來說,QtConcurrent::run() 函數會在一個單獨的線程中執行,并且該線程取自全局 QThreadPool,該函數的返回值通過 QFuture API 提供。
// 需要傳遞的參數,則跟在函數名之后,依次加入 QFuture<void> future = QtConcurrent::run(FuncWithArguments, integer, string);
...
QString result = future.result();
需要注意的是:
1)該函數可能不會立即運行; 函數只有在線程可用時才會運行
2)通過 QtConcurrent::run() 返回的 QFuture 不支持取消、暫停,返回的 QFuture 只能用于查詢函數的運行/完成狀態和返回值
3) Qt Concurrent 已經從 QtCore 中移除并成為了一個獨立的模塊,所以想要使用 QtConcurrent 需要在 pro 文件中導入模塊:
QT += concurrent
?