因为在做的工程项目里使用了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很容易了吧。