【问题标题】:Is there a problem with this usage of boost condition code?这种升压条件代码的使用有问题吗?
【发布时间】:2010-11-05 06:15:11
【问题描述】:

这段代码会在生产者void push(data) 中的互斥体上等待吗?

如果是这样,我该如何解决?

boost::mutex access;
boost::condition cond;

// consumer
data read()
{
  boost::mutex::scoped_lock lock(access);

  // this blocks until the data is ready
  cond.wait(lock);

  // queue is ready
  return data_from_queue();
}

// producer
void push(data)
{
  //<--- will a block ever happen here?
  boost::mutex::scoped_lock lock(access);
  // add data to queue

  cond.notify_one();  
}

假设我有一个线程池 for(;;) 循环,并且我已经从该池中的线程调用了 read()。然后我处理它的数据。我用一些外部线程调用 push() 。我的问题是,该外部线程能否阻止其对 push(data) 的调用?

【问题讨论】:

    标签: c++ boost synchronization conditional-statements


    【解决方案1】:

    当 .wait() 被调用时,它将阻塞线程池中的调用线程并释放互斥锁。它会在有人调用 notify_one() 或 notify_all() 时返回。但是,在被阻塞的线程返回之前,它将重新获取互斥锁并解除线程池中的线程阻塞。

    因此,您的外部线程对void push(data) 的调用只会暂时阻塞,直到调用 .wait() 为止。

    请参阅boost documentation on the condition's wait function

    【讨论】:

    • 这不是真的。 void push(data) 在调用等待之前不会阻塞。只有在无法获取互斥锁时才会阻塞,并且必须等到其他人释放互斥锁。作为旁注,数据 read() 函数必须检查队列中是否确实有项目(可能在未调用 wait() 时添加了项目,或者发生了虚假唤醒)。该函数必须执行“while(queue is empty) cond.wait(lock); return data_from_queue();”
    【解决方案2】:

    wait 可以在不调用 notify 的情况下返回。这称为spurious wakeup。为了处理这个问题,使用条件的代码应该总是在wait 周围有一个循环,以检查预期的条件是否真的有效。例如:

    queue data_queue;
    boost::mutex access;
    boost::condition cond;
    
    // consumer
    data read()
    {
      boost::mutex::scoped_lock lock(access);
    
      while (queue.is_empty()) {
        // this blocks until the data is ready
        cond.wait(lock);
      }
    
      // queue is ready
      return data_from_queue();
    }
    
    // producer
    void push(data)
    {
      boost::mutex::scoped_lock lock(access);
    
      // add data to queue
      queue.push_back(data);
    
      cond.notify_one();  
    }
    

    从概念上讲,“条件”有点误导。相反,您可以将其视为一个信号。您正在向另一个或多个线程发出信号以唤醒,但您并没有承诺任何事情。只是,“嘿,也许有一些数据准备好了,你为什么不去检查一下?”

    【讨论】:

    • 假设我有一个线程池 for(;;) 循环,并且我已经从该池中的线程调用了 read()。然后我处理它的数据。我用一些外部线程调用 push() 。我的问题是,该外部线程能否阻止其对 push(data) 的调用?
    • 假设队列为空()
    • 如另一个答案中的示例, .wait 调用释放互斥体,允许“推送”获取它。
    猜你喜欢
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多