news 2026/5/1 8:43:09

C++ 多线程 std::call_once() and std::once_flag

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 多线程 std::call_once() and std::once_flag

C++ 多线程 std::call_once{} and std::once_flag

  • 1. `std::call_once()`
    • 1.1. `std::once_flag`
  • 2. Parameters
  • 3. Return value
  • 4. Examples
    • 4.1. `std::call_once()`
  • 5. Data races (数据竞争)
  • 6. Exception safety (异常安全性)
  • References

https://cplusplus.com/reference/mutex/call_once/

1.std::call_once()

public member function

template <class Fn, class... Args> void call_once (once_flag& flag, Fn&& fn, Args&&... args);

std::call_once()是 C++11 引入的一个线程同步原语,用于确保在多线程环境中,某个特定的函数或初始化代码块‌仅被执行一次‌,无论有多少个线程同时调用它。

多个线程同时调用std::call_once()时,只有一个线程会执行目标函数,其他线程会被阻塞,直到该函数执行完毕。

Callsfnpassingargsas arguments, unless another thread has already executed (or is currently executing) a call tostd::call_once()with the samestd::once_flag.
调用函数fn并传递args作为参数,除非另一个线程已经执行过 (或正在执行) 使用相同std::once_flag调用std::call_once()的操作。

If another thread is already actively executing a call tostd::call_once()with the samestd::once_flag, it causes a passive execution: Passive executions do not callfnbut do not return until the active execution itself has returned, and all visible side effects are synchronized at that point among all concurrent calls to this function with the samestd::once_flag.

std::call_once()将检查关联的std::once_flag是否已被标记为执行过:

  • 如果没有执行过,则std::call_once()会执行传入的函数,并将标记设置为已执行,保证此后的调用不会再次执行该函数。
  • 如果已执行过,则std::call_once()不会执行传入的函数。
passive ['pæsɪv] n. 被动语态;动词被动形式 adj. 消极的;被动的;(动词形式) 被动语态的

If an active call tostd::call_once()ends by throwing an exception (which is propagated to its calling thread) and passive executions exist, one is selected among these passive executions, and called to be the new active call instead.
如果对std::call_once()的活动调用因抛出异常而终止 (该异常会传播到调用线程),并且存在被动执行,则会从这些被动执行中选择一个,并将其作为新的活动调用来执行。

Note that once an active execution has returned, all current passive executions and future calls tostd::call_once()(with the samestd::once_flag) also return without becoming active executions.
一旦某个活动执行完成并返回,所有当前的被动执行以及将来对std::call_once()的调用 (使用相同的std::once_flag) 也会立即返回,而不会成为活动执行。

The active execution usesstd::decayof thelvalueorrvaluereferences offnandargs, ignoring the value returned byfn.

1.1.std::once_flag

struct once_flag;

Object of this type are used as arguments forstd::call_once().

Using the same object on different calls tostd::call_once()in different threads causes a single execution if called concurrently.

It is a non-copyable, non-movable, default-constructible class, declared in<mutex>with the following prototype:

// STRUCT once_flag struct once_flag { // opaque data structure for call_once() constexpr once_flag() _NOEXCEPT : _Opaque(0) { // default construct } once_flag(const once_flag&) = delete; once_flag& operator=(const once_flag&) = delete; void *_Opaque; };

2. Parameters

  • flag

Object used by the function to track the state of invocations.

Using the same object for calls in different threads, results in a single call if called concurrently.

C++11: Ifflaghas a state that is not valid, the function throws astd::system_errorexception with anstd::errc::invalid_argumenterror condition.

C++14: Ifflaghas a state that is not valid, the call causes undefined behavior.

std::call_once()is a specific type defined in header<mutex>to be used as argument to this function.

std::once_flag应当与需要单次执行的函数或者代码块保持相同的生命周期,通常作为静态状态存在于全局或者作为某个对象的一部分。一旦被std::call_once()标记为已调用,它的状态就不会再变更,确保生命周期的管理不会影响其功能。

  • fn

A pointer to function, pointer to member, or any kind ofstd::is_move_constructiblefunction object (i.e., an object whose class definesoperator(), including closures andstd::functionobjects).

The return value (if any) is ignored.

  • args...

Arguments passed to the call tofn. Their types shall bestd::is_move_constructible.

Iffnis astd::is_member_pointer, the first argument shall be an object for which that member is defined (or a reference, or a pointer to it).

3. Return value

none

4. Examples

4.1.std::call_once()

//============================================================================ // Name : std::call_once() // Author : Yongqiang Cheng // Version : Version 1.0.0 // Copyright : Copyright (c) 2019 Yongqiang Cheng // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <thread> #include <chrono> #include <mutex> int winner; void set_winner(const int x) { winner = x; } std::once_flag winner_flag; void wait_1000ms(const int id) { // count to 1000, waiting 1ms between increments: for (int i = 0; i < 1000; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } // claim to be the winner (only the first such call is executed): std::call_once(winner_flag, set_winner, id); } int main() { std::thread threads[10]; // spawn 10 threads: for (int i = 0; i < 10; ++i) { threads[i] = std::thread(wait_1000ms, i + 1); } std::cout << "waiting for the first among 10 threads to count 1000 ms...\n"; for (auto& th : threads) { th.join(); } std::cout << "winner thread: " << winner << '\n'; return 0; }

Possible output (winner may vary):

waiting for the first among 10 threads to count 1000 ms... winner thread: 9 请按任意键继续. . .

5. Data races (数据竞争)

The function modifiesstd::once_flag, and accessesfnandargsto createstd::decayof theirlvalueorrvaluereferences.

6. Exception safety (异常安全性)

If the function itself fails, it throws astd::system_errorexception, leaving all objects in a valid state (basic guarantee).

Otherwise, active executions provide the same level of guarantees as the operation performed on the arguments.

References

[1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/
[2]std::call_once(), https://cplusplus.com/reference/mutex/call_once/
[3]std::once_flag, https://cplusplus.com/reference/mutex/once_flag/

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 7:10:55

Pi0机器人控制中心GPU加速配置:提升视觉处理性能50%

Pi0机器人控制中心GPU加速配置&#xff1a;提升视觉处理性能50% 如果你正在用Pi0机器人控制中心做视觉相关的任务&#xff0c;可能会发现有时候处理速度不够快&#xff0c;特别是当需要实时分析视频流或者处理高分辨率图像时。其实&#xff0c;只要正确配置GPU加速&#xff0c…

作者头像 李华
网站建设 2026/5/1 6:13:00

基于RexUniNLU的Python爬虫数据智能处理实战教程

基于RexUniNLU的Python爬虫数据智能处理实战教程 你是不是也遇到过这种情况&#xff1f;用Python爬虫辛辛苦苦抓了一大堆网页数据&#xff0c;结果发现全是乱七八糟的文本——人名、地名、公司名混在一起&#xff0c;谁和谁有关系也搞不清楚&#xff0c;想分类整理更是无从下手…

作者头像 李华
网站建设 2026/4/22 13:23:19

使用VSCode调试通义千问3-Reranker-0.6B模型的完整指南

使用VSCode调试通义千问3-Reranker-0.6B模型的完整指南 1. 为什么需要在VSCode里调试Reranker模型 你可能已经下载好了Qwen3-Reranker-0.6B模型&#xff0c;也跑通了基础推理代码&#xff0c;但当结果不如预期时&#xff0c;问题出在哪&#xff1f;是输入格式不对&#xff1f…

作者头像 李华
网站建设 2026/5/1 7:06:02

gemma-3-12b-it应用场景:自媒体运营者截图竞品海报→风格分析+优化建议

Gemma-3-12b-it应用场景&#xff1a;自媒体运营者截图竞品海报→风格分析优化建议 1. 引言 在当今竞争激烈的自媒体领域&#xff0c;如何快速分析竞品海报的设计风格并获取优化建议&#xff0c;是每个运营者都面临的挑战。传统方法需要人工分析色彩、排版、文案等元素&#x…

作者头像 李华
网站建设 2026/4/17 23:01:50

DeepSeek-R1-Distill-Qwen-1.5B模型长期记忆实现:外部知识库集成方案

DeepSeek-R1-Distill-Qwen-1.5B模型长期记忆实现&#xff1a;外部知识库集成方案 1. 为什么小模型也需要长期记忆能力 DeepSeek-R1-Distill-Qwen-1.5B是个很特别的模型。它只有15亿参数&#xff0c;比动辄几十上百亿的大模型轻巧得多&#xff0c;部署起来不费劲&#xff0c;对…

作者头像 李华