Spec-Zone.ru › C++

std::condition_variable::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 приведет к вызову notify для уничтоженного объекта.

Пример

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;
 
std::condition_variable 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/notify_one

Spec-Zone.ru

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