станд :: unique_lock & Lt; станд :: мьютекс & GT; или std :: lock_guard & lt; std :: mutex & gt ;?

У меня есть два варианта использования.

О. Я хочу синхронизировать доступ двумя потоками к очереди.

Б. Я хочу синхронизировать доступ двух потоков к очереди и использовать условную переменную, потому что один из потоков будет ожидать сохранения содержимого в очереди другим потоком.

Для варианта использования A я вижу пример кода, использующего std::lock_guard<>. Для варианта использования B я вижу пример использования кода std::unique_lock<>.

В чем разница между этими двумя и какой я должен использовать в каком случае использования?

272

Решение

Разница в том, что вы можете заблокировать и разблокировать 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,

265

Другие решения

lock_guard а также unique_lock в значительной степени одно и то же; lock_guard является ограниченной версией с ограниченным интерфейсом.

lock_guard всегда держит замок от его строительства до его разрушения. unique_lock может быть создан без немедленной блокировки, может разблокироваться в любой момент своего существования и может передавать право собственности на блокировку из одного экземпляра в другой.

Так что вы всегда используете lock_guard, если вам не нужны возможности unique_lock, condition_variable нужен unique_lock,

87

использование lock_guard если вам не нужно иметь возможность вручную unlock мьютекс между ними, не разрушая lock,

Особенно, condition_variable открывает свой мьютекс, когда ложится спать на звонки wait, Вот почему lock_guard здесь недостаточно

35

Есть определенные общие вещи между lock_guard а также unique_lock и определенные различия.

Но в контексте поставленного вопроса компилятор не позволяет использовать lock_guard в сочетании с условной переменной, потому что, когда поток вызывает ожидание для условной переменной, мьютекс автоматически разблокируется, а когда другой поток / потоки уведомляют об этом, и текущий поток вызывается (выходит из режима ожидания), блокировка повторно устанавливается.

Это явление противоречит принципу lock_guard, lock_guard может быть построен только один раз и разрушен только один раз.

следовательно lock_guard не может использоваться в сочетании с условной переменной, но unique_lock может быть (потому что unique_lock может быть заблокирован и разблокирован несколько раз).

9

Как было упомянуто другими, 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:

  • станд :: condition_variable :: ожидание (станд :: unique_lock&) просто вызывает pthread_cond_wait () для базовой переменной условия pthread относительно мьютекса, хранящегося в unique_lock (и, следовательно, может сделать то же самое для lock_guard, но не делает, потому что стандарт этого не предусматривает)
  • std :: condition_variable_any может работать с любым блокируемым объектом, включая тот, который вообще не является блокировкой мьютекса (следовательно, он может даже работать с семафором между процессами)
-6
По вопросам рекламы [email protected]