Есть ли проблема с таким использованием кода условия наддува?

Будет ли этот код когда-либо ждать мьютекса внутри 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();  
}

Допустим, у меня есть пул потоков для цикла (;;), и у меня есть вызов read () из потока в этом пуле. Затем обрабатываю данные о нем. И я вызываю push () с каким-то внешним потоком. Мой вопрос: может ли этот внешний поток когда-либо блокироваться при вызове push (данных)?


person Net Citizen    schedule 23.06.2009    source источник


Ответы (2)


Когда вызывается .wait (), он блокирует вызывающий поток в вашем пуле потоков и освобождает мьютекс. Он вернется, когда кто-то вызовет notify_one () или notify_all (). Однако, прежде чем поток, который был заблокирован, вернется, он повторно получит мьютекс и разблокирует поток в вашем пуле потоков.

Таким образом, вызов void push(data) вашим внешним потоком будет только временно блокироваться до тех пор, пока не будет вызван .wait ().

См. документацию по boost для функции ожидания условия.

person Brian R. Bondy    schedule 23.06.2009
comment
Это неправда. void push (data) не будет блокироваться, пока не будет вызвано ожидание. Он будет блокироваться только в том случае, если он не может получить мьютекс, и ему придется ждать, пока кто-то другой не освободит мьютекс. В качестве побочного примечания функция data read () ДОЛЖНА проверять, есть ли на самом деле элементы в очереди (возможно, элемент был добавлен, когда он не вызывал wait (), или произошло ложное пробуждение). Функция ДОЛЖНА выполняться, пока (очередь пуста) cond.wait (lock); вернуть data_from_queue (); - person nos; 27.07.2009

wait может вернуться без вызова notify. Это называется ложным пробуждением. Чтобы справиться с этим, код, использующий условие, всегда должен иметь цикл вокруг 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();  
}

Концептуально «состояние» вводит в заблуждение. Вместо этого вы можете думать об этом как о сигнале. Вы сигнализируете другому потоку или потокам проснуться, но вы ничего не обещаете. Просто: «Эй, может быть, есть какие-то данные, почему бы тебе не пойти проверить, а?»

person John Kugelman    schedule 23.06.2009
comment
Допустим, у меня есть пул потоков для цикла (;;), и у меня есть вызов read () из потока в этом пуле. Затем обрабатываю данные о нем. И я вызываю push () с каким-то внешним потоком. Мой вопрос: может ли этот внешний поток когда-либо блокироваться при вызове push (данных)? - person Net Citizen; 23.06.2009
comment
Предположим, например, что очередь пуста () - person Net Citizen; 23.06.2009
comment
Как показано в другом ответе, вызов .wait освобождает мьютекс, позволяя "push" получить его. - person Vladimir Prus; 23.06.2009