Разница в том, что вы можете заблокировать и разблокировать std::unique_lock
. std::lock_guard
будет заблокирован только один раз на строительстве и разблокирован при уничтожении.
Так что для варианта использования B вам определенно нужна std::unique_lock
переменная условия. В случае А это зависит от того, нужно ли вам снова заблокировать охрану.
std::unique_lock
имеет другие функции, которые позволяют ему, например: создавать без немедленной блокировки мьютекса, но создавать оболочку RAII (см. здесь ).
std::lock_guard
также предоставляет удобную оболочку RAII, но не может безопасно заблокировать несколько мьютексов. Его можно использовать, когда вам нужна оболочка для ограниченной области, например, функция-член:
class MyClass{
std::mutex my_mutex;
void member_foo() {
std::lock_guard<mutex_type> lock(this->my_mutex);
/*
block of code which needs mutual exclusion (e.g. open the same
file in multiple threads).
*/
//mutex is automatically released when lock goes out of scope
};
Для уточнения вопроса по chmike, по умолчанию std::lock_guard
и std::unique_lock
так же. Таким образом, в приведенном выше случае, вы можете заменить std::lock_guard
на std::unique_lock
. Тем не менее, std::unique_lock
может иметь немного больше накладных расходов.
Обратите внимание, что в эти дни следует использовать std::scoped_lock
вместо std::lock_guard
.
std::lock_guard
для вашего случая А этого достаточно, то вам следует его использовать. Это не только позволяет избежать ненужных накладных расходов, но также показывает читателю намерение, что вы никогда не разблокируете эту защиту.unique_lock
, вероятно, будут уменьшены стоимостью фактической блокировки и разблокировки мьютекса (если компилятор не оптимизировал эти издержки, что могло бы быть возможным).So for usecase B you definitely need a std::unique_lock for the condition variable
- да, но только в потокеcv.wait()
s, потому что этот метод атомарно освобождает мьютекс. В другом потоке, где вы обновляете общую переменную (переменные) и затем вызываетеcv.notify_one()
,lock_guard
достаточно просто заблокировать мьютекс в области видимости ... если вы не делаете ничего более сложного, что я не могу себе представить! например, en.cppreference.com/w/cpp/thread/condition_variable - у меня работает :)lock_guard
иunique_lock
в значительной степени одно и то же;lock_guard
является ограниченной версией с ограниченным интерфейсом.А
lock_guard
всегда держит замок от его строительства до его разрушения. Aunique_lock
может быть создан без немедленной блокировки, может разблокироваться в любой момент своего существования и может передавать право собственности на блокировку из одного экземпляра в другой.Таким образом, вы всегда используете
lock_guard
, если вам не нужны возможностиunique_lock
. Аcondition_variable
нуженunique_lock
.источник
A condition_variable needs a unique_lock.
- да, но только с тойwait()
стороны, как подробно изложено в моем комментарии к инф.Используйте,
lock_guard
если вам не нужно вручнуюunlock
мьютекс между ними, не разрушаяlock
.В частности,
condition_variable
разблокирует его мьютекс при переходе в режим ожидания при вызовахwait
. Вот почему здесьlock_guard
не достаточно.источник
lock_guard
и разблокировать его, таким образом временно нарушая инвариант класса сторожа. Несмотря на то, что это происходит незаметно для пользователя, я считаю, что это законная причина для недопущения использованияlock_guard
в этом случае.lock_guard
вообще не позволяет получить базовый мьютекс. Это намеренное ограничение, позволяющее более просто рассуждать о коде, который использует,lock_guard
а не о коде, который используетunique_lock
. Единственный способ добиться того, что вы просите, - это сознательно нарушить инкапсуляциюlock_guard
класса и подвергнуть его реализацию другому классу (в данном случае -condition_variable
). Это сложная цена, чтобы заплатить за сомнительное преимущество пользователя условной переменной, которая не должна помнить разницу между двумя типами блокировки.condition_variable_any.wait
будет работать сlock_guard
? Стандарт требует, чтобы предоставленный тип Замка соответствовалBasicLockable
требованию (§30.5.2), которыйlock_guard
не делает. Только его основной мьютекс, но по причинам, которые я указал ранее, интерфейсlock_guard
не обеспечивает доступ к мьютексу.Есть некоторые общие вещи , между
lock_guard
иunique_lock
и некоторые различия.Но в контексте заданного вопроса компилятор не позволяет использовать
lock_guard
в сочетании с условной переменной, потому что, когда поток вызывает ожидание для условной переменной, мьютекс автоматически разблокируется, и когда другие потоки / потоки уведомляют и текущий поток вызывается (выходит из режима ожидания), блокировка восстанавливается.Это явление противоречит принципу
lock_guard
.lock_guard
может быть построен только один раз и разрушен только один раз.Следовательно,
lock_guard
не может использоваться в комбинации с условной переменной, ноunique_lock
может быть (потому чтоunique_lock
может быть заблокирован и разблокирован несколько раз).источник
he compiler does not allow using a lock_guard in combination with a condition variable
Это неверно Это , конечно , это позволяет и работать отлично сlock_guard
наnotify()
ИНГ стороне. Толькоwait()
сторона int требуетunique_lock
, потому чтоwait()
должна снять блокировку при проверке состояния.Они на самом деле не одни и те же мьютексы,
lock_guard<muType>
имеют почти то же самоеstd::mutex
, с той разницей, что их время жизни заканчивается в конце области (называемой D-tor), поэтому четкое определение этих двух мьютексовИ
Вот пример реализации:
В этом примере я использовал
unique_lock<muType>
сcondition variable
источник
Как уже упоминалось другими, std :: unique_lock отслеживает заблокированное состояние мьютекса, поэтому вы можете отложить блокировку до окончания построения блокировки и разблокировать до разрушения блокировки. std :: lock_guard не разрешает это.
Кажется, нет никаких причин, по которым функции ожидания std :: condition_variable не должны принимать lock_guard, а также unique_lock, потому что всякий раз, когда ожидание заканчивается (по любой причине), мьютекс автоматически повторно запрашивается, чтобы не вызывать никакого семантического нарушения. Однако в соответствии со стандартом, чтобы использовать std :: lock_guard с условной переменной, вы должны использовать std :: condition_variable_any вместо std :: condition_variable.
Редактировать : удалено «Использование интерфейса pthreads std :: condition_variable и std :: condition_variable_any должны быть идентичны». Рассматривая реализацию gcc:
источник