std::notify_all_at_thread_exit

来自cppreference.com
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
互斥
(C++11)
(C++11)  
通用锁管理
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
条件变量
notify_all_at_thread_exit
(C++11)
(C++11)
信号量
闩与屏障
(C++20)
(C++20)
未来体
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
(C++26)
风险指针





原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(C++20 中弃用)
(C++11)(C++20 中弃用)
内存定序
原子操作的自由函数
原子标志的自由函数
 
在标头 <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 的所有权转移到内部存储。
  • 修改执行环境,以令当前线程退出时,如同以 lk.unlock();
    cond.notify_all();
    通知条件变量 cond

隐含的 lk.unlock 按顺序晚于与当前线程关联的所有拥有线程局域存储期的对象析构。

如果满足以下任意条件,那么行为未定义:

  • 调用线程没有锁定 lk
  • 在有其他线程也在 cond 上等待的情况下,那些线程在 cond 上调用的等待函数(waitwait_for 以及 wait_until)解锁的互斥与 lk.mutex() 不同。

注解

等价的效果可以用 std::promisestd::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;
ComplexType result; // 某种任意类型
 
void thread_func()
{
    thread_local std::string thread_local_data = "42";
 
    std::unique_lock<std::mutex> lk(m);
 
    // 用 thread_local 数据赋值给 result
    result = thread_local_data;
    ready = true;
 
    std::notify_all_at_thread_exit(cv, std::move(lk));
 
}   // 1. 销毁 thread_local 对象;
    // 2. 解锁互斥体;
    // 3. 通知 cv。
 
int main()
{
    std::thread t(thread_func);
    t.detach();
 
    // 做其他工作
    // .…
 
    // 等待脱附的线程
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{ return ready; });
 
    // result 已就绪且 thread_local 析构函数已完成,无 UB
    assert(result == "42");
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 2140 C++11 notify_all_at_thread_exit 的调用同步于在 cond 上等待的函数的调用 更新同步要求

参阅

设置结果为指定值,同时仅在线程退出时分发提醒
(std::promise<R> 的公开成员函数)
执行函数,并确保结果仅在一旦当前线程退出时就绪
(std::packaged_task<R(Args...)> 的公开成员函数)