因為在做的工程項目里使用了Qt,而實際上不涉及到屏幕顯示,工程代碼里使用了QThread,且沒有使用Qt核心的信號與槽,為了以后移植准備使用更加通用的C++11 stl中的thread取代QThread。
下面是一些測試過程,因為沒有為這個小測試建一個版本控制,所以為了能記錄每步測試修改,這里將編寫代碼編寫博客,開始吧。
1 #include <iostream> 2 #include <thread> 3 #include <chrono> 4 #include <functional> 5 6 using namespace std; 7 8 class MyThread 9 { 10 public: 11 MyThread() 12 { 13 thread t([this]()-> void { 14 15 run(); 16 17 }); 18 t.detach(); 19 } 20 21 public: 22 void run() 23 { 24 for(int i=0;i<5;i++) 25 { 26 cout<<"Hello Nelson!"<<endl; 27 std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 28 } 29 } 30 }; 31 32 int main(int argc,char *argv[]) 33 { 34 35 MyThread mythread; 36 37 cout<<"main thread is over"<<endl; 38 39 return 0; 40 }
上面代碼運行環境,Ubuntu 16.04.4 g++版本:gcc version 5.4.0
先使用VS2008編譯不行,VS2010編譯不行,主要報錯是說沒有std::thread,這里有個文檔,里面有VS各個版本對C++11支持說明,https://blogs.msdn.microsoft.com/vcblog/2011/09/12/c11-features-in-visual-c-11/ (C++11 Features in Visual C++11)。
上述代碼的編譯指令是這樣的:g++ -std=c++11 -pthread test.cpp -o test
注意指定標准C++11和-pthread線程庫鏈接選項,test.c代碼里沒有#include <pthread> ,如果去掉-phtread編譯,結果提示undefined reference to `pthread_create'。運行test,結果如下:

子線程建立后,主線程和子線程的線程調度是不確定的,索引多執行幾次test后,結果會不一樣。因為thread對象調用了detach,所以子線程運行狀態與線程對象完全無關,thread t在構造函數執行完了之后就消亡了。如果驗證子線程在主線程結束了以后還在運行呢?在子線程里向文件里寫內容。
#include <iostream> #include <thread> #include <chrono> #include <functional> #include <fstream> using namespace std; class MyThread { public: MyThread() { thread t([this]()-> void { run(); }); t.detach(); } public: void run() { fstream f; f.open("test.txt",ios::out|ios::trunc); for(int i=0;i<5;i++) { cout<<"Hello Nelson!"<<endl; f<<"Write One Line\n"; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); f<<"Write The Other Line\n"; } f.close(); } }; int main(int argc,char *argv[]) { MyThread mythread; cout<<"main thread is over"<<endl; std::this_thread::sleep_for(std::chrono::milliseconds(10)); //delay for file create return 0; }
編譯運行,結果如下:

和想象中的結果不一致,預期是子線程獨立運行,在文檔中寫入多行文字,而且結果中居然一行也沒有顯示。修改主線程休眠時間,由10ms改為10s,結果如下:

這就說明文件讀寫是很正常的。
主線程關閉時也關閉了子線程?不然無法理解Hello Nelson不接着打印,同時文件寫操作內容不見了。文件寫操作內容不見了則可以說明這種情況下,子線程內部的操作都是不安全的,不可預期的。
下面測試讓主線程主動關閉子線程(通過控制變量bRun做到的),這才是需要的線程基本控制。
1 #include <iostream> 2 #include <thread> 3 #include <chrono> 4 #include <functional> 5 #include <fstream> 6 7 using namespace std; 8 9 class MyThread 10 { 11 private: 12 bool bRun; 13 14 public: 15 void DisableThreadRun() 16 { 17 bRun = false; 18 } 19 20 public: 21 MyThread() 22 { 23 bRun = true; 24 25 thread t([this]()-> void { 26 27 run(); 28 29 }); 30 t.detach(); 31 } 32 33 public: 34 void run() 35 { 36 fstream f; 37 f.open("test.txt",ios::out|ios::trunc); 38 39 while(bRun) 40 { 41 for(int i=0;i<5;i++) 42 { 43 cout<<"Hello Nelson!"<<endl; 44 f<<"Write One Line\n"; 45 std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 46 f<<"Write The Other Line\n"; 47 } 48 f.flush(); 49 } 50 f.close(); 51 cout<<"sub thread is running out"<<endl; 52 } 53 }; 54 55 int main(int argc,char *argv[]) 56 { 57 MyThread mythread; 58 59 std::this_thread::sleep_for(std::chrono::milliseconds(10000)); //delay for file create 60 mythread.DisableThreadRun(); 61 std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 62 63 cout<<"main thread is over"<<endl; 64 65 return 0; 66 }
測試結果如下

主要是子線程函數,這里使用lambda表達式用起來就是非常的爽,【capture】屬性中填入this(參見上一篇博客),lambda表達式中就可以獲得所在類里的所有權限了,直接調用類成員方法run。開起來是不是跟QThread里的Run一樣。
使用C++11的thread去掉QThread很容易了吧。
