std::notify_all_at_thread_exit
Определено в заголовке <condition_variable> | ||
|---|---|---|
void notify_all_at_thread_exit( std::condition_variable& cond,
std::unique_lock<std::mutex> lk );
| (начиная с C++11) |
notify_all_at_thread_exit предоставляет механизм для уведомления других потоков о том, что данный поток полностью завершил работу, включая уничтожение всех объектов thread_local. Он работает следующим образом:
- Владение ранее полученной блокировкой
lkпередаётся во внутреннее хранилище. - Среда выполнения изменяется таким образом, что при завершении текущего потока условная переменная
condполучает уведомление, как если бы это было сделано посредствомlk.unlock();cond.notify_all();.
Подразумеваемая lk.unlock() упорядочена после уничтожения всех объектов с длительностью хранения, локальной для потока, связанных с текущим потоком.
Поведение не определено, если выполняется любое из следующих условий:
-
lkне заблокирована вызывающим потоком. - Если какие-либо другие потоки также ожидают на
cond,lk.mutex()отличается от мьютекса, разблокируемого функциями ожидания (wait,wait_forиwait_until), вызываемыми этими потоками дляcond.
Примечания
Аналогичного эффекта можно добиться с помощью средств, предоставляемых std::promise или std::packaged_task.
Переданная блокировка lk удерживается до завершения потока. После вызова этой функции никакие другие потоки не могут получить ту же блокировку, чтобы ожидать на cond. Если какие-либо потоки ожидают на этой условной переменной, убедитесь, что ожидаемое условие выполнено при удержании блокировки на lk и что эта блокировка не освобождается и не захватывается повторно до вызова notify_all_at_thread_exit, чтобы избежать путаницы из-за ложных пробуждений в других потоках.
В типичных случаях использования эта функция вызывается последней в отсоединённом потоке.
Параметры
| cond | - | условная переменная, которую нужно уведомить при завершении потока |
| lk | - | блокировка, связанная с условной переменной cond |
Возвращаемое значение
(нет)
Пример
Этот фрагмент кода иллюстрирует, как можно использовать notify_all_at_thread_exit, чтобы избежать доступа к данным, зависящим от локальных для потока объектов, пока эти объекты уничтожаются:
#include <cassert>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
std::mutex m;
std::condition_variable cv;
bool ready = false;
std::string result; // some arbitrary type
void thread_func()
{
thread_local std::string thread_local_data = "42";
std::unique_lock<std::mutex> lk(m);
// assign a value to result using thread_local data
result = thread_local_data;
ready = true;
std::notify_all_at_thread_exit(cv, std::move(lk));
} // 1. destroy thread_locals;
// 2. unlock mutex;
// 3. notify cv.
int main()
{
std::thread t(thread_func);
t.detach();
// do other work
// ...
// wait for the detached thread
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{ return ready; });
// result is ready and thread_local destructors have finished, no UB
assert(result == "42");
}
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| Отчёт об ошибке | Применимо к | Опубликованное поведение | Правильное поведение |
|---|---|---|---|
| LWG 2140 | C++11 | вызов notify_all_at_thread_exitсинхронизирован с вызовами функций, ожидающих на cond | требование к синхронизации обновлено |
См. также
| задаёт результат определённым значением, выполняя уведомление только при завершении потока (открытая функция-член std::promise<R>) |
|
| выполняет функцию, гарантируя, что результат будет готов только после завершения текущего потока (открытая функция-член std::packaged_task<R(Args...)>) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/thread/notify_all_at_thread_exit