尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++20 atomic::wait 与 notify:等待状态变化,不必一直空转

C++20 atomic::wait 与 notify:等待状态变化,不必一直空转 C20 atomic::wait 与 notify等待状态变化不必一直空转如果线程只需要等待一个原子状态改变循环 load 加 sleep 虽然容易写却很难兼顾延迟与资源占用。C20 为原子对象增加 wait、notify_one 和 notify_all让这种简单等待更直接。最低标准C20且标准库需要实现原子等待。下面是一次性数据发布不是通用消息队列。1. 改状态然后通知#includeatomic#includeiostream#includestring#includethreadintmain(){std::atomicboolready{false};std::string message;std::threadconsumer([]{ready.wait(false,std::memory_order_acquire);std::coutmessage\n;});messagedata is ready;ready.store(true,std::memory_order_release);ready.notify_one();consumer.join();}输出 data is ready。消费者等待 ready 不再等于 false生产者先写数据再以 release 存储 true然后唤醒等待者。对应的 acquire 观察到这次发布后消费者才能安全读取此前写好的普通字符串。2. 通知不是状态本身只 notify 不改变值不能让等待条件成立。反过来只 store 改值却不 notify也不能保证已经阻塞的等待者及时被唤醒。常见正确顺序是先更新状态再通知。若生产者在消费者进入 wait 前已经把值改为 truewait 检查到当前值不同会直接返回因此一次性状态不会因为“通知早了一点”就丢失。3. wait 比较的是值不记录事件次数底层等待可能被虚假唤醒但 atomic::wait 会继续检查只在观察到值不等于给定旧值时返回。不过值若从 A 变为 B 又变回 A等待者可能完全错过中间变化这就是需要注意的 ABA 问题。所以不能用一个 bool 的快速翻转来可靠计数每一次事件。需要消息、多个任务或事件数量时应设计队列、计数协议或者使用适合的同步原语。4. 内存序和生命周期都不能省略思考notify 本身不替代 release/acquire 的数据发布关系。若改成 relaxed 并仍让两个线程无保护地读写同一个普通对象就不能凭“已经通知了”断言安全。示例中 ready 与 message 活到消费者 join 之后而且 message 在发布后不再被并发修改。通用组件也必须保证等待中的原子对象不被销毁。C20 的原子等待没有直接的带超时成员函数要等待复杂谓词或实现超时condition_variable 往往更合适。简单单状态等待用 atomic::wait复杂状态协调仍要选择与需求匹配的工具。进一步阅读C 标准草案中的原子等待操作。
返回列表