2015-11-13 8 views
4

В документации для std :: condition_variable есть перегрузка wait(), принимающая в качестве аргумента функцию предиката. Функция будет ждать до первого wake_up, при котором функция предиката будет true.std :: condition_variable :: wait with predicate

В documentation

Он заявил, что это эквивалентно:

while (!pred()) { 
    wait(lock); 
} 

Но также:

Эта перегрузка может быть использована, чтобы игнорировать паразитные пробуждений во время ожидания для конкретного условие, чтобы оно стало истинным. Обратите внимание, что перед входом в этот метод блокировка должна быть получена, после того, как выйдет (блокировка), она также будет восстановлена, т. Е. Блокировка может использоваться как защита для доступа pred().

Я не уверен, чтобы понять, являются эти strictrly эквивалент (в этом случае я предпочитаю равнину в то время как цикл, который легче читать, чем перегрузка с лямбда в моем случае), либо перегрузка (возможно, реализация зависит) более эффективны?

Может ли реализация оценить предикат в уведомляющем потоке до пробуждения ожидающего потока, чтобы избежать пробуждения, когда условие теста ложно? C++ нить гуру нужен здесь ...

Благодаря

ответ

0

Насколько я понимаю, идет эти два (а while петлю и wait + predicate) функционально эквивалентны. Если вы используете цикл while, блокировка должна быть получена до ввода и оценки состояния цикла в первый раз. В любой другой момент вы также удерживаете замок, как predicate() будет выполнен после завершения wait().

Перегрузка внутренне делает то же самое: вам необходимо получить блокировку перед вызовом wait, а после того, как ожидание завершено, внутренне вызывается predicate(), чтобы проверить, следует ли нам продолжать ждать (как и в цикле).

Возможно, вы правы, для простых предикатов, которые просто возвращают значение boolean, используя цикл while, яснее. Но что делать, если predicate становится более сложным? Определите для него выделенную функцию и используйте ее в состоянии цикла while или используйте lambda? Что, если число предикатов будет расти, вы определите функцию для каждого из них? На мой взгляд, использование lambdas в этом случае делает код более четким, поскольку целые вещи хранятся вместе в одном логическом блоке.

2

Реализации могут попытаться сделать его лучше, чем цикл с точки зрения производительности, но я сомневаюсь, что это возможно. Это очень сложно, и вы можете проверить свою реализацию, чтобы увидеть, как это делается. Это то, что GCC 4.9.2 делает здесь:

template<typename _Predicate> 
    void 
    wait(unique_lock<mutex>& __lock, _Predicate __p) 
    { 
     while (!__p()) 
     wait(__lock); 
    } 

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

cond_var.wait(lock, []() { return bool_var == true; }) 
+0

Это было мое понимание цели этой функции. Но из документации я понял, что перегрузка может избежать пробуждения потока в случаях, когда переменная не изменилась. Это означало бы, что объект Predicate оценивается в другом потоке (например, уведомляющий поток), прежде чем эффективно пробуждать ожидающий поток. Таким образом, более эффективно – galinette

+0

@ galinette Нет, не может. Он основан на условных переменных pthread, и у них есть ложные пробуждения. – SergeyA

+0

Стандарт не основан на pthreads, ни на всех реализациях. И потоки окон имеют больше возможностей, чем pthreads в этом отношении, если я прав (поскольку я использую mingw-gcc у меня есть выбор) – galinette

 Смежные вопросы

  • Нет связанных вопросов^_^