views:

659

answers:

2

Will this code ever wait on the mutex inside the producer's void push(data)?

If so how do I get around that?

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();  
}

Let's say I have a thread pool for(;;) loop and I have read() being called from a thread in this pool. Then I process data on it. And I call push() with some external thread. My question is, can that external thread ever block on its call to push(data)?

+4  A: 

wait can return without notify ever being called. This is called a spurious wakeup. To handle this, code using a condition should always have a loop around the wait that checks that the expected condition really is in effect. For example:

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();  
}

Conceptually, "condition" is kind of misleading. Instead you can think of it as a signal. You are signalling another thread or threads to wake up, but you are not promising anything. Just, "Hey, maybe there's some data ready, why don't you go check eh?"

John Kugelman
Let's say I have a thread pool for(;;) loop and I have read() being called from a thread in this pool. Then I process data on it. And I call push() with some external thread. My question is, can that external thread ever block on its call to push(data)?
Net Citizen
Assume for example that the queue is empty()
Net Citizen
Won't the access mutex be held until it returns from read()?
Net Citizen
As exampled in the other answer, .wait call releases the mutex, allowing 'push' to acquire it.
Vladimir Prus
+1  A: 

When .wait() is called it will block the calling thread in your thread pool and release the mutex. It will return when someone calls notify_one() or notify_all(). Before the thread that was blocked returns though, it will re-acquire the mutex and unblock the thread in your thread pool.

So the call to void push(data) by your external thread will only block temporarily up until .wait() is called.

See the boost documentation on the condition's wait function.

Brian R. Bondy
This is not true. void push(data) will not block until a wait is called. It will only block if it cannot aquire the mutex, and have to wait until someone else releases the mutex.As a side note the data read() function MUST check wether there are actually items in the queue (maybe an item was added while it was not calling wait(), or a spurious wakeup occured). The function HAVE to do "while(queue is empty) cond.wait(lock); return data_from_queue();"
nos