条件变量不工作,但添加 std::cout 后,它工作

Posted

技术标签:

【中文标题】条件变量不工作,但添加 std::cout 后,它工作【英文标题】:The conditional variable is not working but after adding std::cout, it is working 【发布时间】:2015-06-15 07:40:33 【问题描述】:

我的项目由两个线程组成:一个主线程和另一个处理另一个窗口内容的线程。所以,当主线程想要请求另一个窗口更新自己时,它调用了如下的绘制函数:

void SubApplicationManager::draw() 

  // Zero number of applications which has finished the draw counter
  
    boost::lock_guard<boost::mutex> lock(SubApplication::draw_mutex);
    SubApplication::num_draws = 0;
  

  // Draw the sub applications.
  for (size_t i = 0; i < m_subApplications.size(); i++)
    m_subApplications[i].signal_draw();

  // Wait until all the sub applications finish drawing.
  while (true)
    boost::lock_guard<boost::mutex> lock(SubApplication::draw_mutex);
    std::cout << SubApplication::num_draws << std::endl;
    if (SubApplication::num_draws >= m_subApplications.size()) break;
  


draw 函数只是通知另一个线程收到了新任务。

void SubApplication::signal_draw() 

  task = TASK::TASK_DRAW;
  
    boost::lock_guard<boost::mutex> lock(task_received_mutex);
    task_received = true;
  
  task_start_condition.notify_all();


其他线程的主体如下。它等待任务到达,然后开始处理:

void SubApplication::thread() 

  clock_t start_time, last_update;
  start_time = last_update = clock();

  //! Creates the Sub Application
  init();

  while (!done)                                                       // Loop That Runs While done=FALSE
  
      // Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
      if (active)                                       // Program Active?
      
        // Wait here, until a update/draw command is received.
        boost::unique_lock<boost::mutex> start_lock(task_start_mutex);
        while (!task_received)
          task_start_condition.wait(start_lock);
        

        // Task received is set to false, for next loop.
        
          boost::lock_guard<boost::mutex> lock(task_received_mutex);
          task_received = false;
        

        clock_t frame_start_time = clock();

        switch (task)
        case TASK_UPDATE:
          update();
          break;

        case TASK_DRAW:
          draw();
          swapBuffers();
          break;

        case TASK_CREATE:
          create();
          break;

        default:
          break;
        

        clock_t frame_end_time = clock();
        double task_time = static_cast<float>(frame_end_time - frame_start_time) / CLOCKS_PER_SEC;

      
  

问题是,如果我按原样运行代码,它永远不会使用task = TASK::TASK_DRAW; 运行另一个线程,但如果我在SubApplication::draw() 的开头添加std::cout &lt;&lt; "Draw\n";,它会正常运行。我正在寻找它发生的原因以及修复它的常用方法是什么?

【问题讨论】:

您需要在此处显示 SSCCE。这留下了太多的猜测。根据我们在此处看到的内容,我提供了一个“提示”答案。这是 SSCCE 的开始:paste.ubuntu.com/11718487 说白了,你好像不明白条件变量的全部目的,就是提供一个原子的“解锁等待”功能,避免等待已经发生的事情。 【参考方案1】:
boost::lock_guard<boost::mutex> lock(task_received_mutex);
task_received = true;

好的,task_received_mutex 保护task_received

    boost::unique_lock<boost::mutex> start_lock(task_start_mutex);
    while (!task_received)
      task_start_condition.wait(start_lock);
    

糟糕,我们正在读取task_received,但没有持有保护它的互斥锁。是什么阻止了一个线程读取task_received 而另一个线程正在修改它的竞争?这可能会立即导致死锁。

此外,您的代码声称“等待所有子应用程序完成绘制”,但没有调用任何等待函数。所以它实际上是在旋转而不是等待,这很糟糕。

【讨论】:

【参考方案2】:

首先,在task_start_mutex 锁定下发送task_start_condition 信号。

考虑在线程创建期间锁定该互斥体以避免明显的竞争。

第三:您似乎有几个以“逻辑任务”(绘制、启动)命名的互斥锁。然而,实际上,互斥锁保护资源,而不是“逻辑任务”。因此,以他们应该保护的共享资源命名它们是一种很好的做法。 _(在这种情况下,我的印象是单个互斥体可能就足够/更好了。但我们无法从显示的代码中确定)。

【讨论】:

以上是关于条件变量不工作,但添加 std::cout 后,它工作的主要内容,如果未能解决你的问题,请参考以下文章

如何轻松使 std::cout 线程安全?

蓝桥ROS机器人之现代C++学习笔记7.4 条件变量

多次调用std :: cout会使子进程挂起

R 检查不喜欢 std:cout (C++)

为啥 std::cout 输出溢出?

std :: cout可以在Windows上使用UTF-8吗?