当前位置:   article > 正文

生产者-消费者C++实现(一)_c++ 生产者消费者代码实现

c++ 生产者消费者代码实现

和同学闲聊,谈到多线程中的经典问题——生产者-消费者问题:要求实现两个线程,一个线程负责对全局变量进行+1操作,一个线程负责打印更新后的值。自己从事code多年,自以为对多线程了解深入,不假思索,写出了下面的代码:

  1. #include <iostream>
  2. #include <mutex>
  3. #include <thread>
  4. #include <iostream>
  5. #include <condition_variable>
  6. static volatile bool g_flag = true; //线程运行标志
  7. static volatile int g_value = 0; //打印变量
  8. static std::condition_variable g_cond; //条件变量
  9. static std::mutex g_mutex; //互斥锁
  10. //打印线程入口函数
  11. void print_thread(void)
  12. {
  13. printf("print thread enter \n");
  14. while (g_flag) {
  15. std::unique_lock<std::mutex> lk(g_mutex);
  16. auto ret = g_cond.wait_for(lk, std::chrono::milliseconds(5000));
  17. if (ret == std::cv_status::no_timeout) {
  18. std::cout << "pppppppppp print thread " << g_value << std::endl;
  19. } else {
  20. printf("print thread wait timeout\n");
  21. }
  22. }
  23. printf("print thread leave \n");
  24. }
  25. //计算线程入口函数
  26. void add_thread(void)
  27. {
  28. printf("add thread enter \n");
  29. while (g_value < 10) {
  30. {
  31. std::unique_lock<std::mutex> lk(g_mutex);
  32. g_value++;
  33. std::cout << "++++++++++ add thread " << g_value << std::endl;
  34. }
  35. g_cond.notify_one();
  36. }
  37. printf("add thread leave \n");
  38. }
  39. int main(int argc, char **argv)
  40. {
  41. std::thread thread_print(print_thread);
  42. std::thread thread_add(add_thread);
  43. getchar();
  44. g_flag = false;
  45. if (thread_print.joinable())
  46. thread_print.join();
  47. if (thread_add.joinable())
  48. thread_add.join();
  49. return 0;
  50. }

运行之后,结果令我很尴尬:

分析原因,试着在分析线程调用g_cond.notify_one()之后添加等待,代码如下:

  1. void add_thread(void)
  2. {
  3. printf("add thread enter \n");
  4. while (g_value < 10) {
  5. {
  6. std::unique_lock<std::mutex> lk(g_mutex);
  7. g_value++;
  8. std::cout << "++++++++++ add thread " << g_value << std::endl;
  9. }
  10. g_cond.notify_one();
  11. std::this_thread::sleep_for(std::chrono::seconds(1));
  12. }
  13. printf("add thread leave \n");
  14. }

就这样,问题解决了:

由此可知,是由于计算线程运行太快,而打印线程运行慢,造成condition_variable信号丢失导致。很明显,要解决这样的问题,在计算线程增加等待不是一个好的解决方案,因为等待时间不好控制:时间太短,打印线程没有处理完,仍会导致condition_variable信号丢失;时间太长,导致打印线程等待,造成时间浪费。新的方案,使用两个condition_variable,一个用于等待打印,一个用于等待计算,代码如下:

  1. #include <iostream>
  2. #include <mutex>
  3. #include <thread>
  4. #include <iostream>
  5. #include <condition_variable>
  6. volatile bool g_flag = true; //运行标志
  7. volatile int g_value = 0; //变量
  8. volatile bool g_print_able = false; //是否可以打印
  9. std::condition_variable g_cond_add_enable; //计算条件变量
  10. std::condition_variable g_cond_print_enable; //打印条件变量
  11. std::mutex g_mutex;
  12. //打印线程入口函数
  13. void print_thread(void)
  14. {
  15. printf("print thread enter \n");
  16. while (g_flag) {
  17. {
  18. std::unique_lock<std::mutex> lk(g_mutex);
  19. g_cond_print_enable.wait(lk, [&] {return g_print_able; }); //等待打印
  20. std::cout << "pppppppppp print thread " << g_value << std::endl;
  21. g_print_able = false;
  22. }
  23. g_cond_add_enable.notify_one(); //通知计算
  24. }
  25. printf("print thread leave \n");
  26. }
  27. //计算线程入口函数
  28. void add_thread(void)
  29. {
  30. printf("add thread enter \n");
  31. while (g_value < 10) {
  32. if (g_value != 0) {
  33. std::unique_lock<std::mutex> lk(g_mutex);
  34. g_cond_add_enable.wait(lk, [] {return !g_print_able; }); //等待计算
  35. g_value++;
  36. std::cout << "++++++++++ add thread " << g_value << std::endl;
  37. g_print_able = true;
  38. } else { //第一次计算,不等待,直接计算,否则造成死锁
  39. g_value++;
  40. g_print_able = true;
  41. std::cout << "++++++++++ add thread " << g_value << std::endl;
  42. }
  43. g_cond_print_enable.notify_one(); //通知打印
  44. }
  45. printf("add thread leave \n");
  46. }
  47. int main(int argc, char **argv)
  48. {
  49. std::thread thread_print(print_thread);
  50. std::thread thread_add(add_thread);
  51. getchar();
  52. g_flag = false;
  53. if (thread_print.joinable())
  54. thread_print.join();
  55. if (thread_add.joinable())
  56. thread_add.join();
  57. return 0;
  58. }

打印结果如下:

当然,这种方案仅适用于生产者,消费者性能处理相当的情况。如果生产者,消费者处理性能相差较大,该种方案并不合适。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/267897
推荐阅读
相关标签
  

闽ICP备14008679号