std:: уникально замок или std:: предохранитель замка?
у меня есть два варианта использования.
A. Я хочу синхронизировать доступ двумя потоками к очереди.
B. Я хочу синхронизировать доступ двумя потоками к очереди и использовать переменную условия, потому что один из потоков будет ждать содержимого, которое будет храниться в очереди другим потоком.
для случая использования я вижу пример кода с использованием std::lock_guard<>. Для случая использования B я вижу пример кода с помощью std::unique_lock<>.
Что такое разница между ними и какой из них следует использовать в каком случае?
5 ответов:
разница в том, что вы можете заблокировать и разблокировать
std::unique_lock.std::lock_guardбудет заблокирован только один раз на строительстве и разблокирован при разрушении.так что для использования случая B вам определенно нужен
std::unique_lockдля переменной условия. В случае A это зависит от того, нужно ли вам снова заблокировать охрану.
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может быть немного больше накладных расходов.
lock_guardиunique_lockв значительной степени то же самое;lock_guard- это ограниченная версия с ограниченным интерфейсом.A
lock_guardвсегда держит замок от своей конструкции к своему разрушению. Аunique_lockможет быть создан без немедленной блокировки, может разблокировать в любой момент своего существования и может передавать право собственности на блокировку от одного экземпляра к другому., так что вы всегда использовать
lock_guard, Если вам не нужны возможностиunique_lock. Аcondition_variableнуженunique_lock.
использовать
lock_guardЕсли вам не нужно быть в состоянии вручнуюunlockмьютекс между ними, не уничтожаяlock.в частности,
condition_variableразблокирует свой мьютекс, когда собирается спать по вызовамwait. Вот почемуlock_guardздесь недостаточно.
есть некоторые общие вещи между
lock_guardиunique_lockи определенные различия.но в контексте заданного вопроса, компилятор не позволит использовать
lock_guardв сочетании с переменной условия, потому что когда поток вызывает ожидание переменной условия, мьютекс автоматически разблокируется, и когда другие потоки/потоки уведомляют и текущий поток вызывается (выходит из ожидания), блокировка повторно приобретается.это явление против принципа
lock_guard.lock_guardможет быть построен только один раз и разрушен только один раз.отсюда
lock_guardне может использоваться в сочетании с переменной условия, ноunique_lockможет быть (потому чтоunique_lockможет быть заблокирован и разблокирован несколько раз).
Как уже упоминалось другими, std:: unique_lock отслеживает заблокированное состояние мьютекса, поэтому вы можете отложить блокировку до тех пор, пока не построите замок, и разблокировать до разрушения замка. std:: lock_guard не разрешает этого.
кажется, нет причин, по которым функции ожидания std::condition_variable не должны принимать lock_guard, а также unique_lock, потому что всякий раз, когда ожидание заканчивается (по какой-либо причине), мьютекс автоматически повторно запрашивается, так что это не вызовет любое семантическое нарушение. Однако согласно стандарту, чтобы использовать std::lock_guard с переменной условия, вы должны использовать std::condition_variable_any вместо std:: condition_variable.
Edit: удалено "использование интерфейса pthreads std::condition_variable и std:: condition_variable_any должны быть идентичны". При взгляде на реализацию gcc:
- std:: condition_variable:: wait (std::unique_lock&) просто вызывает pthread_cond_wait() на базовая переменная условия pthread относительно мьютекса, удерживаемого unique_lock (и поэтому может одинаково делать то же самое для lock_guard, но не потому, что стандарт этого не предусматривает)
- std:: condition_variable_any может работать с любым блокируемым объектом, включая тот, который вообще не является блокировкой мьютекса (поэтому он может работать даже с межпроцессным семафором)
Comments