Windows 多线程编程入门(2)

前端之家收集整理的这篇文章主要介绍了Windows 多线程编程入门(2)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

简单总结下C++自带的 std::thread
优点:
1. 简单,易用
2. 跨平台,pthread只能用在POSIX系统上(其他系统有其独立的thread实现)
3. 提供了更多高级功能,比如future
4. 更加C++(跟匿名函数,std::bind,RAII等C++特性更好的集成

缺点:
1. 没有RWlock。有一个类似的shared_mutex,不过它属于C++14,你的编译器很有可能不支持
2. 操作线程和Mutex等的API较少。毕竟为了跨平台,只能选取各原生实现的子集。如果你需要设置某些属性,需要通过API调用返回原生平台上的对应对象,再对返回的对象进行操作。

joinable函数
检查线程是否可被 join。检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的。另外,如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的。

  1. t.joinable();

native_handle函数
由于 std::thread 的实现和操作系统相关,因此该函数返回与 std::thread 具体实现相关的线程句柄,例如在符合 Posix 标准的平台下(如 Unix/Linux)是 Pthread 库

yield函数
当前线程放弃执行,操作系统调度另一线程继续执行。

  1. std::this_thread::yield();

hardware_concurrency 函数
函数为静态函数,用于检测硬件并发特性,返回当前平台的线程实现所支持的线程并发数目,但返回值仅仅只作为系统提示(hint)。

条件变量
作为线程同步的重要方法,std::thread,也支持了condition_variable:当某些条件不满足时,停止执行直到该条件被满足。

在经典的生产者消费者模式下,生产者和消费者就是通过condition variable来实现同步的。当有限的生产力无法满足日益增长的消费需求时,消费者进程就会去睡一觉,直到它想要的东西生产出来才醒来

condition_variable需要和 unique_lock搭配使用。在一个线程调用wait之前,它必须持有unique_lock锁。当wait被调用时,该锁会被释放,线程会陷入沉睡,等待着王子生产者发过来的唤醒信号。当生产者调用同一个condition_variable的 notify_all方法时,所有沉睡在该变量前的消费者会被唤醒,并尝试重新获取之前释放的unique_lock,继续执行下去。(注意这里发生了锁争用,只有一个消费者能够获得锁,其他消费者得等待该消费者释放锁)。如果只想叫醒一个线程,可以用notify_one

wait可以接受两个参数。此时第二个参数用于判断当前是否要沉睡

  1. []{ return msgQueue.size() > 0;});
  2.  
  3. while (msgQueue.size() <= 0) {
  4. condvar.wait()
  5. }

这里把沉睡的线程比作睡美人,万一王子变成了青蛙,来不及唤醒她,那睡美人不就得睡到天荒地老海枯石烂?

为了解决这个问题,通过wait_until和wait_for,你可以设定线程的等待时间。设置notify_all_at_thread_exit也许能帮得上忙。

atomic
它提供了一组轻量级的、作用在单个变量上的原子操作。atomic位于头文件atomic。内容不会被线程的切换所打断。

  1. /*time:20180605 author:MISAYAONE */
  2. #include<iostream>
  3. #include<thread>
  4. #include<Windows.h>
  5. #include<mutex>
  6. #include<condition_variable>
  7. #include<queue>
  8. using namespace std;
  9.  
  10. mutex mu_msg;
  11. condition_variable cv_msg;
  12. //消费者,生产者模式的简单实现(利用条件变量和互斥锁)
  13. queue<int> msg_queue;
  14. void producer(int start,int end)
  15. {
  16. for (int i=start;i<end;i++)
  17. {
  18. mu_msg.lock();
  19. msg_queue.push(i);
  20. mu_msg.unlock();
  21. }
  22. cout << "msg produced" << endl;
  23. if (msg_queue.size() > 20)
  24. {
  25. cv_msg.notify_all();//沉睡在该变量上的所有线程都将被唤醒,并尝试获取互斥锁(只有一个消费者可获得互斥锁)
  26. }
  27. }
  28.  
  29. void consumer(int demand)
  30. {
  31. while (true)
  32. {
  33. unique_lock<std::mutex> ulock(mu_msg);
  34. cv_msg.wait(ulock,[] {return msg_queue.size() > 0;});//尝试获取互斥锁,否则等待
  35. printf("Consume msg %d\n",msg_queue.front());
  36. msg_queue.pop();
  37. --demand;
  38. if (!demand)
  39. {
  40. break;
  41. }
  42. }
  43. }
  44.  
  45. mutex mu;//互斥锁对象
  46.  
  47. int num = 100;
  48. void thread_func1()
  49. {
  50. for (int i=0;i<10;i++)
  51. {
  52. cout <<"thread 1's "<< i << endl;
  53. Sleep(100);
  54. }
  55.  
  56. while (num>0)//这里不能用while,好无知....
  57. {
  58. mu.lock();//互斥锁加锁
  59. cout << "1还在执行" << num << endl;
  60. num--;
  61. mu.unlock();//互斥锁解锁
  62. if (num < 50)
  63. {
  64. //当前线程就不再执行
  65. this_thread::yield();
  66. break;
  67. }
  68. }
  69.  
  70.  
  71.  
  72.  
  73. }
  74.  
  75. void thread_func2(int n)
  76. {
  77. for (int i = 0; i<n; i++)
  78. {
  79. cout <<"thread 2's "<< i << endl;
  80. Sleep(200);
  81. }
  82. while (num>0)
  83. {
  84. mu.lock();
  85. cout <<"2还在执行"<< num << endl;
  86. num--;
  87. mu.unlock();
  88. }
  89.  
  90. }
  91.  
  92. class A
  93. {
  94. public :
  95. void thread_func3()
  96. {
  97. for (int i = 0; i<10; i++)
  98. {
  99. cout << "class A thread 3's " << i << endl;
  100. Sleep(200);
  101. }
  102. }
  103.  
  104. };
  105.  
  106. class thread_guard
  107. {
  108. thread &t;
  109. public:
  110. explicit thread_guard(thread& _t):t(_t){}
  111. ~thread_guard()
  112. {
  113. if (t.joinable())
  114. {
  115. t.join();
  116. }
  117. }
  118. //拷贝赋值默认去除
  119. thread_guard(const thread_guard&) = delete;
  120. thread_guard& operator=(const thread_guard&) = delete;
  121. };
  122.  
  123. int main()
  124. {
  125. A a;
  126. thread task00();//默认构造函数
  127.  
  128. thread task01(thread_func1);//正常构造函数
  129. thread_guard g(task01);//出现异常后,函数退出,g局部对象对销毁,此时g调用析构函数,会自动执行task01的join函数,从而能够保证join一定会被调用
  130. thread task02(thread_func2,10);//带args的线程构造函数
  131. //thread task_i(move(task02));//转移线程所有权,此时再利用task02调用join和detach会报错
  132. thread task03(&A::thread_func3,a);//传入类的成员函数作为线程构造函数的参数
  133.  
  134. if (task01.joinable())//此处不可以使用task00线程来判断
  135. {
  136. cout << "task01 is joinable" << endl;
  137. }
  138.  
  139.  
  140. //join函数顺序执行线程
  141. task01.join();
  142. task02.join();
  143. //task_i.join();
  144. //task03.join();
  145.  
  146. //不影响当前代码的执行,几个线程后台自行执行,不阻塞主线程
  147. //task01.detach();
  148. //task02.detach();
  149. //task_i.detach();
  150. task03.detach();
  151.  
  152. //lambda匿名函数
  153. for (int j=0;j<20;j++)
  154. {
  155. thread t([j]() {cout << j << endl; });
  156. t.detach();
  157. }
  158.  
  159. for (int i = 0; i<10; i++)
  160. {
  161. cout << "main thread's " << i << endl;
  162. Sleep(200);
  163. }
  164.  
  165. cout << "task01.get_id() = " << task01.get_id() << endl;//获取线程ID
  166.  
  167. unsigned int core_num = std::thread::hardware_concurrency();
  168. cout << "cpu 核数" << core_num << endl;
  169.  
  170. thread mutiple00(producer,10,20);
  171. thread mutiple01(producer,20,30);
  172. thread mutiple02(producer,30,40);
  173. thread mutiple03(consumer,5);
  174. thread mutiple04(consumer,8);
  175.  
  176. mutiple00.join();
  177. mutiple01.join();
  178. mutiple02.join();
  179. mutiple03.join();
  180. mutiple04.join();
  181.  
  182.  
  183. cin.get();
  184. return 0;
  185. }

猜你在找的Windows相关文章