std:: уникально замок или std:: предохранитель замка?



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



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



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



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



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

461   5  

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

    Ничего не найдено.