C++11并发之std::thread的使用方法

http://blog.csdn.net/liuker888/article/details/46848905

http://www.cnblogs.com/lidabo/p/7852033.html

 

知识链接:

C++11 并发之std::mutex

C++11 并发之std::atomic

 

本文概要:

1、成员类型和成员函数。

2、std::thread 构造函数。

3、异步。

4、多线程传递参数。

5、join、detach。

6、获取CPU核心个数。

7、CPP原子变量与线程安全。

8、lambda与多线程。

9、时间等待相关问题。

10、线程功能拓展。

11、多线程可变参数。

12、线程交换。

13、线程移动。

 

std::thread 在 #include<thread> 头文件中声明,因此使用 std::thread 时需要包含 #include<thread> 头文件。

 

1、成员类型和成员函数。

成员类型:

id

Thread id (public member type )                                       id

native_handle_type

Native handle type (public member type )

成员函数:

(constructor)

Construct thread (public member function )        构造函数

(destructor)

Thread destructor (public member function )      析构函数

operator=

Move-assign thread (public member function )  赋值重载

get_id

Get thread id (public member function )                获取线程id

joinable

Check if joinable (public member function )          判断线程是否可以加入等待

join

Join thread (public member function )                    加入等待

detach

Detach thread (public member function )              分离线程

swap

Swap threads (public member function )               线程交换

native_handle

Get native handle (public member function )       获取线程句柄

hardware_concurrency [static]

Detect hardware concurrency (public static member function )   检测硬件并发特性

Non-member overloads:

swap (thread)

Swap threads (function )

 

2、std::thread 构造函数。

如下表:

default (1)

thread() noexcept;

initialization(2)

template <class Fn, class... Args>   explicit thread (Fn&& fn, Args&&... args);

copy [deleted] (3)

thread (const thread&) = delete;

move [4]

hread (thread&& x) noexcept;

(1).默认构造函数,创建一个空的 thread 执行对象。

(2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。

(3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。

(4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。

注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。

 

std::thread 各种构造函数例子如下:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. #include<chrono>  
  4. using namespace std;  
  5. void fun1(int n)  //初始化构造函数  
  6. {  
  7.     cout << "Thread " << n << " executing\n";  
  8.     n += 10;  
  9.     this_thread::sleep_for(chrono::milliseconds(10));  
  10. }  
  11. void fun2(int & n) //拷贝构造函数  
  12. {  
  13.     cout << "Thread " << n << " executing\n";  
  14.     n += 20;  
  15.     this_thread::sleep_for(chrono::milliseconds(10));  
  16. }  
  17. int main()  
  18. {  
  19.     int n = 0;  
  20.     thread t1;               //t1不是一个thread  
  21.     thread t2(fun1, n + 1);  //按照值传递  
  22.     t2.join();  
  23.     cout << "n=" << n << '\n';  
  24.     n = 10;  
  25.     thread t3(fun2, ref(n)); //引用  
  26.     thread t4(move(t3));     //t4执行t3,t3不是thread  
  27.     t4.join();  
  28.     cout << "n=" << n << '\n';  
  29.     return 0;  
  30. }  
  31. 运行结果:  
  32. Thread 1 executing  
  33. n=0  
  34. Thread 10 executing  
  35. n=30</span>  

 

3、异步。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. void show()  
  5. {  
  6.     cout << "hello cplusplus!" << endl;  
  7. }  
  8. int main()  
  9. {  
  10.     //栈上  
  11.     thread t1(show);   //根据函数初始化执行  
  12.     thread t2(show);  
  13.     thread t3(show);  
  14.     //线程数组  
  15.     thread th[3]{thread(show), thread(show), thread(show)};   
  16.     //堆上  
  17.     thread *pt1(new thread(show));  
  18.     thread *pt2(new thread(show));  
  19.     thread *pt3(new thread(show));  
  20.     //线程指针数组  
  21.     thread *pth(new thread[3]{thread(show), thread(show), thread(show)});  
  22.     return 0;  
  23. }</span>  

 

4、多线程传递参数。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. void show(const char *str, const int id)  
  5. {  
  6.     cout << "线程 " << id + 1 << " :" << str << endl;  
  7. }  
  8. int main()  
  9. {  
  10.     thread t1(show, "hello cplusplus!", 0);  
  11.     thread t2(show, "你好,C++!", 1);  
  12.     thread t3(show, "hello!", 2);  
  13.     return 0;  
  14. }  
  15. 运行结果:  
  16. 线程 1线程 2 :你好,C++!线程 3 :hello!  
  17. :hello cplusplus!</span>  

发现,线程 t1、t2、t3 都执行成功!

 

5、join、detach。

join例子如下:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. #include<array>  
  4. using namespace std;  
  5. void show()  
  6. {  
  7.     cout << "hello cplusplus!" << endl;  
  8. }  
  9. int main()  
  10. {  
  11.     array<thread, 3>  threads = { thread(show), thread(show), thread(show) };  
  12.     for (int i = 0; i < 3; i++)  
  13.     {  
  14.         cout << threads[i].joinable() << endl;//判断线程是否可以join  
  15.         threads[i].join();//主线程等待当前线程执行完成再退出  
  16.     }  
  17.     return 0;  
  18. }  
  19. 运行结果:  
  20. hello cplusplus!  
  21. hello cplusplus!  
  22. 1  
  23. hello cplusplus!  
  24. 1  
  25. 1</span>  

总结:

join 是让当前主线程等待所有的子线程执行完,才能退出。

detach例子如下:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. void show()  
  5. {  
  6.     cout << "hello cplusplus!" << endl;  
  7. }  
  8. int main()  
  9. {  
  10.     thread th(show);  
  11.     //th.join();   
  12.     th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。  
  13.     //detach以后,子线程会成为孤儿线程,线程之间将无法通信。  
  14.     cout << th.joinable() << endl;  
  15.     return 0;  
  16. }  
  17. 运行结果:  
  18. hello cplusplus!  
  19. 0</span>  

结论:

线程 detach 脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。

线程 detach以后,子线程会成为孤儿线程,线程之间将无法通信。

 

6、获取CPU核心个数。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. int main()  
  5. {  
  6.     auto n = thread::hardware_concurrency();//获取cpu核心个数  
  7.     cout << n << endl;  
  8.     return 0;  
  9. }  
  10. 运行结果:  
  11. 8</span>  

结论:

通过  thread::hardware_concurrency() 获取 CPU 核心的个数。

 

7、CPP原子变量与线程安全。

问题例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. const int N = 100000000;  
  5. int num = 0;  
  6. void run()  
  7. {  
  8.     for (int i = 0; i < N; i++)  
  9.     {  
  10.         num++;  
  11.     }  
  12. }  
  13. int main()  
  14. {  
  15.     clock_t start = clock();  
  16.     thread t1(run);  
  17.     thread t2(run);  
  18.     t1.join();  
  19.     t2.join();  
  20.     clock_t end = clock();  
  21.     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
  22.     return 0;  
  23. }  
  24. 运行结果:  
  25. num=143653419,用时 730 ms</span>  

从上述代码执行的结果,发现结果并不是我们预计的200000000,这是由于线程之间发生冲突,从而导致结果不正确。

为了解决此问题,有以下方法:

(1)互斥量。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. #include<mutex>  
  4. using namespace std;  
  5. const int N = 100000000;  
  6. int num(0);  
  7. mutex m;  
  8. void run()  
  9. {  
  10.     for (int i = 0; i < N; i++)  
  11.     {  
  12.         m.lock();  
  13.         num++;  
  14.         m.unlock();  
  15.     }  
  16. }  
  17. int main()  
  18. {  
  19.     clock_t start = clock();  
  20.     thread t1(run);  
  21.     thread t2(run);  
  22.     t1.join();  
  23.     t2.join();  
  24.     clock_t end = clock();  
  25.     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
  26.     return 0;  
  27. }  
  28. 运行结果:  
  29. num=200000000,用时 128323 ms</span>  

不难发现,通过互斥量后运算结果正确,但是计算速度很慢,原因主要是互斥量加解锁需要时间。

互斥量详细内容 请参考C++11 并发之std::mutex

(2)原子变量。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. #include<atomic>  
  4. using namespace std;  
  5. const int N = 100000000;  
  6. atomic_int num{ 0 };//不会发生线程冲突,线程安全  
  7. void run()  
  8. {  
  9.     for (int i = 0; i < N; i++)  
  10.     {  
  11.         num++;  
  12.     }  
  13. }  
  14. int main()  
  15. {  
  16.     clock_t start = clock();  
  17.     thread t1(run);  
  18.     thread t2(run);  
  19.     t1.join();  
  20.     t2.join();  
  21.     clock_t end = clock();  
  22.     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
  23.     return 0;  
  24. }  
  25. 运行结果:  
  26. num=200000000,用时 29732 ms</span>  

不难发现,通过原子变量后运算结果正确,计算速度一般。

原子变量详细内容 请参考C++11 并发之std::atomic。

(3)加入 join 。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. const int N = 100000000;  
  5. int num = 0;  
  6. void run()  
  7. {  
  8.     for (int i = 0; i < N; i++)  
  9.     {  
  10.         num++;  
  11.     }  
  12. }  
  13. int main()  
  14. {  
  15.     clock_t start = clock();  
  16.     thread t1(run);  
  17.     t1.join();  
  18.     thread t2(run);  
  19.     t2.join();  
  20.     clock_t end = clock();  
  21.     cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
  22.     return 0;  
  23. }  
  24. 运行结果:  
  25. num=200000000,用时 626 ms</span>  

不难发现,通过原子变量后运算结果正确,计算速度也很理想。

 

8、lambda与多线程。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. int main()  
  5. {  
  6.     auto fun = [](const char *str) {cout << str << endl; };  
  7.     thread t1(fun, "hello world!");  
  8.     thread t2(fun, "hello beijing!");  
  9.     return 0;  
  10. }  
  11. 运行结果:  
  12. hello world!  
  13. hello beijing!</span>  

 

9、时间等待相关问题。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. #include<chrono>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.     thread th1([]()  
  8.     {  
  9.         //让线程等待3秒  
  10.         this_thread::sleep_for(chrono::seconds(3));  
  11.         //让cpu执行其他空闲的线程  
  12.         this_thread::yield();  
  13.         //线程id  
  14.         cout << this_thread::get_id() << endl;  
  15.     });  
  16.     return 0;  
  17. }</span>  

 

10、线程功能拓展。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. class MyThread :public thread   //继承thread  
  5. {  
  6. public:  
  7.     //子类MyThread()继承thread()的构造函数  
  8.     MyThread() : thread()  
  9.     {  
  10.     }  
  11.     //MyThread()初始化构造函数  
  12.     template<typename T, typename...Args>  
  13.     MyThread(T&&func, Args&&...args) : thread(forward<T>(func), forward<Args>(args)...)  
  14.     {  
  15.     }  
  16.     void showcmd(const char *str)  //运行system  
  17.     {  
  18.         system(str);  
  19.     }  
  20. };  
  21. int main()  
  22. {  
  23.     MyThread th1([]()  
  24.     {  
  25.         cout << "hello" << endl;  
  26.     });  
  27.     th1.showcmd("calc"); //运行calc  
  28.     //lambda  
  29.     MyThread th2([](const char * str)  
  30.     {  
  31.         cout << "hello" << str << endl;  
  32.     }, " this is MyThread");  
  33.     th2.showcmd("notepad");//运行notepad  
  34.     return 0;  
  35. }  
  36. 运行结果:  
  37. hello  
  38. //运行calc  
  39. hello this is MyThread  
  40. //运行notepad</span>  

 

11、多线程可变参数。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. #include<cstdarg>  
  4. using namespace std;  
  5. int show(const char *fun, ...)  
  6. {  
  7.     va_list ap;//指针  
  8.     va_start(ap, fun);//开始  
  9.     vprintf(fun, ap);//调用  
  10.     va_end(ap);  
  11.     return 0;  
  12. }  
  13. int main()  
  14. {  
  15.     thread t1(show, "%s    %d    %c    %f""hello world!", 100, 'A', 3.14159);  
  16.     return 0;  
  17. }  
  18. 运行结果:  
  19. hello world!    100    A    3.14159</span>  

 

12、线程交换。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. int main()  
  5. {  
  6.     thread t1([]()  
  7.     {  
  8.         cout << "thread1" << endl;  
  9.     });  
  10.     thread t2([]()  
  11.     {  
  12.         cout << "thread2" << endl;  
  13.     });  
  14.     cout << "thread1' id is " << t1.get_id() << endl;  
  15.     cout << "thread2' id is " << t2.get_id() << endl;  
  16.       
  17.     cout << "swap after:" << endl;  
  18.     swap(t1, t2);//线程交换  
  19.     cout << "thread1' id is " << t1.get_id() << endl;  
  20.     cout << "thread2' id is " << t2.get_id() << endl;  
  21.     return 0;  
  22. }  
  23. 运行结果:  
  24. thread1  
  25. thread2  
  26. thread1' id is 4836  
  27. thread2' id is 4724  
  28. swap after:  
  29. thread1' id is 4724  
  30. thread2' id is 4836</span>  

两个线程通过 swap 进行交换。

 

13、线程移动。

例如:

[cpp] view plain copy

  1. <span style="font-size:12px;">#include<iostream>  
  2. #include<thread>  
  3. using namespace std;  
  4. int main()  
  5. {  
  6.     thread t1([]()  
  7.     {  
  8.         cout << "thread1" << endl;  
  9.     });  
  10.     cout << "thread1' id is " << t1.get_id() << endl;  
  11.     thread t2 = move(t1);;  
  12.     cout << "thread2' id is " << t2.get_id() << endl;  
  13.     return 0;  
  14. }  
  15. 运行结果:  
  16. thread1  
  17. thread1' id is 5620  
  18. thread2' id is 5620</span>  

从上述代码中,线程t2可以通过 move 移动 t1 来获取 t1 的全部属性,而 t1 却销毁了。

 

 

c++ thread也挺好用的,也可以像qt thread那样,start启动,run函数为线程的实际运行代码。thread和this_thread方法不多,常用的就几个。

 

1.std::this_thread::get_id 获取线程id

2.yield,和sleep。yield,交出cpu占有权,一般可以放到多线程的循环里,减少cpu空转

3.一般代码构建完thread,线程跑起来detach一下,qt是默认会detach的。join实际代码一般不用,就主线程等待其他多个线程结束会用到下。

 

[cpp] view plain copy

  1. #include <thread>  
  2.   
  3. class TestThread  
  4. {  
  5. public:  
  6.     void start(){   
  7.         thread t(std::bind(&TestThread::run,this));  
  8.         t.detach();  
  9.     }  
  10.   
  11.   
  12.     void run(){  
  13.         while (true){  
  14.             cout << "test thread id:" << std::this_thread::get_id()<<endl;  
  15.             std::this_thread::sleep_for(std::chrono::milliseconds(2000));  
  16.         }  
  17.     }  
  18. };  
  19.   
  20.   
  21. void run(){  
  22.     while (true){  
  23.         cout << "function thread id:" << std::this_thread::get_id() << endl;  
  24.         std::this_thread::sleep_for(std::chrono::milliseconds(2000));  
  25.     }  
  26. }  
  27.   
  28.   
  29. int main(void)  
  30. {  
  31.     cout << "main thread id:" << std::this_thread::get_id() << endl;  

[cpp] view plain copy

  1. TestThread testThread;  
  2. testThread.start();  

[cpp] view plain copy

  1.     thread funcThread(&run);  
  2.     funcThread.detach();  
  3.   
  4.     getchar();  
  5.     return 0;  
  6. }  

 

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值