C++11并发之std::thread

C++11并发之std::thread
知识链接:
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、成员类型和成员函数。
成员类型:

成员函数:

Non-member overloads:

2、std::thread 构造函数。
如下表:
(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 却销毁了。

转载于:https://www.cnblogs.com/mmc9527/p/10427924.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/425627.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

极角排序的几种方法

转载自http://www.cnblogs.com/aiguona/p/7248311.html&#xff01;&#xff01; 关于极角排序&#xff1a; 在平面内取一个定点O&#xff0c;叫极点&#xff0c;引一条射线Ox&#xff0c;叫做极轴&#xff0c;再选定一个长度单位和角度的正方向&#xff08;通常取逆时针方向&a…

[剑指offer][JAVA]面试题第[16]题[数值的整数次方][位运算][二分法]

【问题描述】[中等] 实现函数double Power(double base, int exponent)&#xff0c;求base的exponent次方。不得使用库函数&#xff0c;同时不需要考虑大数问题。示例 1:输入: 2.00000, 10 输出: 1024.00000 示例 2:输入: 2.00000, -2 输出: 0.25000 解释: 2-2 1/22 1/4 0.…

玩转oracle 11g(50):rman备份脚本

D盘新建一个文件夹backup_file&#xff0c;里面新建一个文件夹logs 一个文件叫auto_full_one_rman.bat 修改这三处 set oracle_sidwiicare rman cmdfile D:/backup_file/level_full_one_rman.rman msglog D:/backup_file/logs/full_one_%date:~0,4%%date:~5,2%%date:~8,2%…

Java学习笔记7-2——注解与反射

目录理解 Class 类并获取 Class 实例Class类获取 Class 类的实例哪些类型可以有Class对象所有类型的Class对象从内存角度分析类加载【重点】类加载的过程什么时候会发生类的初始化类加载器获取运行时类的完整结构有了Class对象能做什么性能对比分析通过反射操作泛型通过反射操作…

python实战学习之matplotlib绘图续

学习完matplotlib绘图可以设置的属性&#xff0c;还需要学习一下除了折线图以外其他类型的图如直方图&#xff0c;条形图&#xff0c;散点图等&#xff0c;matplotlib还支持更多的图&#xff0c;具体细节可以参考官方文档&#xff1a;https://matplotlib.org/gallery/index.htm…

Spring MVC面试题

目录概述什么是Spring MVC&#xff1f;简单介绍下你对Spring MVC的理解&#xff1f;Spring MVC的优点核心组件Spring MVC的主要组件&#xff1f;什么是DispatcherServlet什么是Spring MVC框架的控制器&#xff1f;Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决…

5.应用服务器简介

应用服务器简介 Tomcat

NOI-砝码称重v2 多重背包 生成函数

描述 设有1g、2g、3g、5g、10g、20g的砝码各若干枚&#xff08;其总重<100,000&#xff09;&#xff0c;要求&#xff1a;计算用这些砝码能称出的不同重量的个数&#xff0c;但不包括一个砝码也不用的情况。 输入 一行&#xff0c;包括六个正整数a1,a2,a3,a4,a5,a6&#x…

vue-touchjs

支持vue2.0的面向指令的touch指令&#xff0c;基于touchjs&#xff08;原百度实现的移动端手势库&#xff09; vue-touchjs支持三种stopPropagation的方式&#xff1a; 1 .stop修饰符 2 事件handler里面调用stopPropagation方法 3 事件handler里面return false 支持的事件&…

Java学习笔记8-1——汇编语言入门

目录概述进制运算二进制数据宽度无符号数和有符号数原码、反码、补码位运算位运算实现加减乘除汇编学习环境和必要说明汇编语言通用寄存器内存未完待续概述 为什么要学习汇编语言 进制运算 运算的本质是查表 二进制 略 为什么要学习理解二进制&#xff1f; 寄存器、内存、…

数字图像与数字图像处理

数字图像与数字图像处理 1、基本概念 &#xff08;1&#xff09;图&#xff1a;是物体反射或者透射电磁波的分布。 &#xff08;2&#xff09;像&#xff1a;是人的视觉系统对接收的图信息在大脑 中形成的印象。 &#xff08;3&#xff09;图像(image)&#xff1a;是“图”和…

[剑指offer][JAVA]面试题第[46]题[把数字翻译成字符串][递归][逆推]

【问题描述】[中等] 给定一个数字&#xff0c;我们按照如下规则把它翻译为字符串&#xff1a;0 翻译成 “a” &#xff0c;1 翻译成 “b”&#xff0c;……&#xff0c;11 翻译成 “l”&#xff0c;……&#xff0c;25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函…

LVM分区无损增减

http://www.361way.com/change-lvm-size/1792.html转载于:https://www.cnblogs.com/augusite/p/10431263.html

前端基础1——HTML5

目录初识HTML网页基本标签列表表格视频和音频页面结构内联框架表单语法初识HTML Hyper Text Markup Language&#xff08;超文本标记语言&#xff09; <!--DOCTYPE&#xff1a;告诉浏览器使用什么规范&#xff08;默认是html&#xff09;--> <!DOCTYPE html> <…

数字图像处理系统组成 及研究内容

数字图像处理系统组成 及研究内容 .数字图像处理系统的组成 基本图象处理系统的结构 图像输入设备 扫描仪分辨率与扫描图象的大小 分辨率&#xff1a;单位长度上采样的像素个数DPI(dot/inch) 图像输出设备 喷墨打印机 激光打印机 数字印刷机 .图像处理技术研究的内容 图…

[剑指offer][JAVA]面试题第[18]题[删除链表的节点]

【问题描述】[中等] 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。返回删除后的链表的头节点。注意&#xff1a;此题对比原题有改动示例 1:输入: head [4,5,1,9], val 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点&#xff0…

Python3 循环

L [Bart, Lisa, Adam] for i in L:print("这是for循环的" "输出 hello:" i.upper())i 0 while i < len(L):print("这是while 循环的输出 hello:" L[i])i i 1转载于:https://www.cnblogs.com/RHadoop-Hive/p/10432219.html

HDU 6168 Numbers 思维

本题就是告诉你有两个数串 其中第一个数串中的每两个元素ai和aj&#xff08;i<j&#xff09;相加得到的元素 放入第二个数串里 但由于两个数串给搞的比较混乱 需要解决从中识别出第一个数串并将其输出出来 本题其实仔细一想就能发现 这个问题 我们从数串的特点上考虑 第二…

前端基础2——CSS3

目录什么是CSSCSS的导入方式选择器美化网页元素盒子模型浮动定位什么是CSS Cascading Style Sheet 层叠级联样式表 CSS&#xff1a;表现层&#xff08;美化网页&#xff09; 字体&#xff0c;颜色&#xff0c;边距&#xff0c;高宽&#xff0c;背景图片&#xff0c;网页定位&…

Socket常见错误代码与描述

如错误代码10061&#xff0c; 说明服务器已经找到&#xff0c;但连接被服务器拒绝&#xff0c; 连接失败原因可能是&#xff1a; 端口号设置错误&#xff1b; 2.服务器没有处于监听状态 &#xff08;即ServerSocket –>Activetrue&#xff09;&#xff1b; 3.数据包被服务…