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 оптимизация? Если да, то как именно это быстрее?

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

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

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

Я проголосовал за ответ cmeerw, потому что считаю, что он привел техническую причину. Давайте пройдемся по нему. Давайте представим, что комитет решил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
}

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

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

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

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
}
Этот код настолько прост, насколько это возможно.Это исключение безопасно.wait функция может проверитьlk.owns_lock() и бросить исключение, если оноfalse.

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

Дополнительно,condition_variable::wait не беретlock_guard<mutex> потому чтоlock_guard<mutex> как вы говорите: я владею замком на этом мьютексе доlock_guard<mutex> Уничтожает. Но когда вы звоните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<mutex> элемент данных.

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

 Howard Hinnant27 окт. 2012 г., 20:42
<nod> Ах, шаблонcondition_variable::wait, Да,condition_variable_any это путь И причина того, что функциональность не складывается вcondition_variable в том, что это дороже. А такжеcondition_variable это инструмент такого низкого уровня, он должен быть как можно более эффективным. Вы платите только за добавленную функциональность, если используетеcondition_variable_any.
 lucas clemente28 окт. 2012 г., 01:18
Вау, я поражен твоим ответом. Большое спасибо за этот уровень детализации!
 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 с простым мьютексом.

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

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

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

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