Spec-Zone.ru › C++

std::condition_variable_any::notify_one

void notify_one() noexcept;
(since C++11)

Если какие-либо потоки ожидают на *this, вызов notify_one разблокирует один из ожидающих потоков.

Параметры

(нет)

Возвращаемое значение

(нет)

Примечания

Эффекты notify_one()/notify_all() и каждого из трёх атомарных частей wait()/wait_for()/wait_until() (разблокировка+ожидание, пробуждение и блокировка) происходят в едином общем порядке, который можно рассматривать как порядок модификации атомарной переменной: порядок специфичен для данной конкретной переменной условия. Это делает невозможным, например, задержку notify_one() и разблокировку потока, который начал ожидание сразу после вызова notify_one().

Уведомляющий поток не обязан удерживать блокировку на том же мьютексе, что и ожидающий поток(и); на самом деле, это ухудшает производительность, поскольку уведомлённый поток сразу же заблокируется снова, ожидая, пока уведомляющий поток освободит блокировку. Тем не менее, некоторые реализации (в частности, многие реализации pthreads) распознают эту ситуацию и избегают этого сценария «поспеши и жди», переведя ожидающий поток из очереди переменной условия непосредственно в очередь мьютекса внутри вызова notify, не пробуждая его.

Уведомление при блокировке всё же может потребоваться, когда требуется точное планирование событий, например, если ожидающий поток завершит программу, если условие выполнено, что приведёт к уничтожению переменной условия уведомляющего потока. Ложное пробуждение после разблокировки мьютекса, но перед уведомлением, приведёт к вызову notify для уничтоженного объекта.

Пример

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;
 
std::condition_variable_any cv;
std::mutex cv_m;
int i = 0;
bool done = false;
 
void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []{ return i == 1; });
    std::cout << "...finished waiting; i == " << i << '\n';
    done = true;
}
 
void signals()
{
    std::this_thread::sleep_for(200ms);
    std::cout << "Notifying falsely...\n";
    cv.notify_one(); // waiting thread is notified with i == 0.
                     // cv.wait wakes up, checks i, and goes back to waiting
 
    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done) 
    {
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns
        std::this_thread::sleep_for(300ms);
        lk.lock();
    }
}
 
int main()
{
    std::thread t1(waits), t2(signals);
    t1.join(); 
    t2.join();
}

Возможный вывод:

Waiting... 
Notifying falsely...
Notifying true change...
...finished waiting; i == 1

См. также

notify_all
уведомляет все ожидающие потоки
(публичный член-функция)
C документация для cnd_signal

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/condition_variable_any/notify_one

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API