разблокировать мьютекс после condition_variable :: notify_all () или до? - PullRequest
0 голосов
/ 25 сентября 2018

Глядя на несколько видео и пример документации , мы разблокируем мьютекс перед тем, как вызовет notify_all().Будет ли лучше вместо этого вызывать его после?

Общий способ:

Внутри потока уведомлений:

//prepare data for several worker-threads;

//and now, awaken the threads:
std::unique_lock<std::mutex> lock2(sharedMutex);
_threadsCanAwaken = true;

lock2.unlock(); 
_conditionVar.notify_all(); //awaken all the worker threads;

//wait until all threads completed;

//cleanup:
_threadsCanAwaken = false;

//prepare new batches once again, etc, etc

Внутри одного израбочие потоки:

while(true){
    // wait for the next batch:

    std::unique_lock<std::mutex> lock1(sharedMutex);
    _conditionVar.wait(lock1,  [](){return _threadsCanAwaken});
    lock1.unlock(); //let sibling worker-threads work on their part as well

    //perform the final task

    //signal the notifier that one more thread has completed;

    //loop back and wait until the next task
}

Обратите внимание, как разблокируется lock2 до того, как мы уведомим переменную условия - нужно ли вместо этого разблокировать после notify_all()?

Редактировать

Из моего комментария ниже: Меня беспокоит то, что, если потребитель очень быстр.Потребитель внезапно просыпается, видит, что мьютекс разблокирован, завершает задачу и возвращается к началу времени.Теперь медленно работающий источник наконец вызывает notify_all (), заставляя потребителя зацикливаться еще раз.

Ответы [ 2 ]

0 голосов
/ 28 июля 2019

Как упомянуто здесь: cppreference.com

Поток-уведомитель не должен удерживать блокировку на том же мьютексе, что и блокировка, ожидаемая ожидающим потоком (-ами);на самом деле это является пессимизацией, поскольку уведомленный поток немедленно снова блокируется, ожидая, когда уведомляющий поток снимет блокировку.

При этом документация для ожидания

В момент блокировки потока функция автоматически вызывает lck.unlock (), что позволяет другим заблокированным потокам продолжить.

После уведомления (явно, каким-либо другим потоком),Функция разблокирует и вызывает lck.lock (), оставляя lck в том же состоянии, что и при вызове функции.Затем функция возвращается (обратите внимание, что эта последняя блокировка мьютекса может снова заблокировать поток перед возвратом).

, поэтому при уведомлении ожидание повторно попытается получить блокировку, и в этом процессе она снова будет заблокированапока оригинальная уведомляющая нить не снимет блокировку.Поэтому я предлагаю снять блокировку перед вызовом уведомления.Как сделано в примере на cppreference.com и, что наиболее важно,

Не будьте пессимистами.

0 голосов
/ 25 сентября 2018

мы должны вместо этого разблокировать его после notify_all ()?

Правильно сделать это в любом случае, но вы можете вести себя по-разному в разных ситуациях.Довольно сложно предсказать, как это повлияет на производительность вашей программы - я видел как положительные, так и отрицательные эффекты для разных приложений.Так что лучше профилировать свою программу и принимать решение по конкретной ситуации на основе профилирования.

...