C ++ 11: почему std :: condition_variable использует std :: unique_lock?

Я немного запутался в ролиstd::unique_lock при работе сstd::condition_variable, Насколько я понялдокументация,std::unique_lock это в основном раздутая защита замка с возможностью смены состояния между двумя замками.

мы до сих пор использовалиpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) для этой цели (я думаю, чточто STL использует в posix). Требуется мьютекс, а не замок.

Какие'Разница здесь? Является ли тот факт, чтоstd::condition_variable имеет дело сstd::unique_lock оптимизация? Если да, то как именно это быстрее?

 lucas clemente27 окт. 2012 г., 14:45
почему переменная условия использует уникальную блокировку, а не мьютекс? этот.
 Brady27 окт. 2012 г., 13:41
Вы не понимаете, зачем вам нужен блокировка / мьютекс с условной переменной, или о разнице между блокировкой и мьютексом или о том, почему переменная условия использует уникальную блокировку, а не мьютекс? "

Ответы на вопрос(2)

Решение Вопроса

Я проголосовал cmeerw 'ответ, потому что я считаю, что он дал техническую причину. Позволять'пройти через это. Позволять's делать вид, что комитет решилcondition_variable подождиmutex, Вот код, использующий этот дизайн:

void foo()
{
    mut.lock();
    // mut locked by this thread here
    while (not_ready)
        cv.wait(mut);
    // mut locked by this thread here
    mut.unlock();
}

Это именно то, как одинне должен использоватьcondition_variable, В регионах отмечены:

// mut locked by this thread here

Существует проблема безопасности исключений, и это серьезная проблема. Если исключение выдается в этих областях (илиcv.wait само по себе), заблокированное состояние мьютекса просачивается, если только где-нибудь не вставлен try / catch, чтобы перехватить исключение и разблокировать его. Но это'просто больше кода выпросим программиста написать.

Позволять'скажем, что программист знает, как написать безопасный код исключения, и знает, как использоватьunique_lock добиться этого. Теперь код выглядит так:

void foo()
{
    unique_lock<mutex> lk(mut);
    // mut locked by this thread here
    while (not_ready)
        cv.wait(*lk.mutex());
    // mut locked by this thread here
}
</mutex>

Это намного лучше, но это все еще не очень хорошая ситуация.condition_variable Интерфейс заставляет программиста изо всех сил пытаться заставить вещи работать. Возможно разыменование нулевого указателя, еслиlk случайно не ссылается на мьютекс. И нет возможности дляcondition_variable::wait чтобы убедиться, что этот поток владеет блокировкой.mut

О, только что вспомнил, есть также опасность, что программист может выбрать неправильныйunique_lock функция-член для раскрытия мьютекса.*lk.release() было бы катастрофическим здесь.

Теперь давайтепосмотрим, как код написан с фактическимcondition_variable API, который принимает:unique_lock

void foo()
{
    unique_lock<mutex> lk(mut);
    // mut locked by this thread here
    while (not_ready)
        cv.wait(lk);
    // mut locked by this thread here
}
</mutex>
Этот код настолько прост, насколько это возможно.Это исключение безопасно.wait функция может проверитьlk.owns_lock() и бросить исключение, если оно есть.false

Это технические причины, которые привели к разработке API.condition_variable

Дополнительно,condition_variable::wait Безразлично»взятьlock_guard так какlock_guard как вы говорите: я владею замком на этом мьютексе доlock_guard Уничтожает. Но когда вы звонитеcondition_variable::waitВы неявно освобождаете блокировку мьютекса. Так что действие несовместимо сlock_guard случай использования / утверждение.

Нам нужноunique_lock во всяком случае, чтобы можно было возвращать блокировки из функций, помещать их в контейнеры и блокировать / разблокировать мьютексы в шаблонах без границ безопасным способом, поэтомуunique_lock был естественным выбором для.condition_variable::wait

Обновить

Bamboon предложил в комментариях ниже, что я контрастируюcondition_variable_anyтак что здесь идет:

Вопрос: Почему нетcondition_variable::wait таким образом, чтобы я мог пройти любойLockable типа к этому?

Ответ:

Это действительно крутая функциональность. НапримерЭта бумага демонстрирует код, который ждет наshared_lock (rwlock) в режиме общего доступа к условной переменной (что-то неслыханное в мире posix, но тем не менее очень полезное). Однако функциональность дороже.

Таким образом, комитет представил новый тип с этой функциональностью:

`condition_variable_any`

С этимcondition_variable адаптер можно ждатьлюбой запираемый тип. Если у него есть участникиlock() а такжеunlock(), ты в порядке. Правильная реализацияcondition_variable_any требуетcondition_variable элемент данных иshared_ptr элемент данных.

Потому что эта новая функциональность дороже, чем ваш основнойcondition_variable::wait, и потому чтоcondition_variable Это такой низкоуровневый инструмент, этот очень полезный, но более дорогой функционал был помещен в отдельный класс, так что вы платите за него, только если используете его.

 lucas clemente28 окт. 2012 г., 01:18
Вау яЯ поражен вашим ответом. Большое спасибо за этот уровень детализации!
 Howard Hinnant27 окт. 2012 г., 20:42
кивок> Ах, шаблонcondition_variable::wait, Да,condition_variable_any это путь И причина того, что функциональность несложить вcondition_variable в том, что это дороже. А такжеcondition_variable это инструмент такого низкого уровня, он должен быть как можно более эффективным. Вы платите только за добавленную функциональность, если используете.condition_variable_any
 inf27 окт. 2012 г., 20:39
Извини, забудь об этом. Я полностью забыл о <condition_variable_any
 Howard Hinnant27 окт. 2012 г., 20:37
Не могли бы вы уточнитьЭто", Вы говорите оlock_guard, или жеcondition_variableили возможно?condition_variable::wait
 inf27 окт. 2012 г., 20:44
Хорошо, спасибо за дополнительную информацию. Возможно добавьте это к своему ответу, поскольку можно было бы неправильно использоватьcondition_variable_any с простым мьютексом.
 Howard Hinnant27 окт. 2012 г., 20:54
Хорошее предложение, спасибо. Готово.

По сути, это решение по разработке API, чтобы сделать API максимально безопасным по умолчанию (с дополнительными издержками, которые рассматриваются как незначительные). Требуя передатьunique_lock вместо сырогоmutex пользователи API направлены на написание правильного кода (при наличии исключений).

В последние годы акцент языка C ++ сместился в сторону обеспечения его безопасности по умолчанию (но все же он позволяет пользователям вставать на ноги, если они этого хотят, и стараться изо всех сил).

 lucas clemente27 окт. 2012 г., 18:03
так что нет технической причины?

Ваш ответ на вопрос