You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

call_once异常场景下的行为:函数未执行完成抛异常时once_flag的值是什么?

std::call_once in Exception Scenarios: Behavior and once_flag State

Let's dive into how std::call_once behaves when the target function throws an exception before completing, and what that means for the associated std::once_flag.

Behavior When the Target Function Throws

The core purpose of std::call_once is to guarantee a function runs exactly once across all threads. But if that function throws an exception before finishing execution, this counts as a failed attempt. Here's the breakdown:

  • The exception gets propagated straight back to the thread that initiated the call_once call.
  • Any other threads blocked waiting on the same once_flag will wake up, and one of them will retry running the target function.
  • This cycle repeats until one invocation of the function completes successfully (no exceptions thrown) — at that point, call_once marks the flag as "done", and no further invocations will happen.

What's the "State" of once_flag After a Failed Execution?

First, a quick clarification: std::once_flag is an opaque type — you can't directly read its internal value or state via any public API. But we can infer its state from how call_once behaves:

  • If the target function throws before completing, the once_flag stays in its initial, untriggered state. It does NOT get marked as "completed".
  • This means subsequent calls to std::call_once with the same flag will still attempt to run the target function, just like the first time.

Example to Illustrate

Here's a simple code snippet that shows this behavior in action:

#include <iostream>
#include <mutex>
#include <stdexcept>
#include <thread>

std::once_flag g_flag;
int g_attempts = 0;

void failing_function() {
    g_attempts++;
    std::cout << "Attempt " << g_attempts << ": Throwing exception\n";
    throw std::runtime_error("Something went wrong!");
}

void working_function() {
    g_attempts++;
    std::cout << "Attempt " << g_attempts << ": Executing successfully\n";
}

int main() {
    // First call: function throws
    try {
        std::call_once(g_flag, failing_function);
    } catch (const std::exception& e) {
        std::cout << "Caught exception: " << e.what() << "\n";
    }

    // Second call: since flag wasn't marked as done, we try again with a working function
    std::call_once(g_flag, working_function);

    std::cout << "Total attempts made: " << g_attempts << "\n";
    return 0;
}

When you run this, the output will be:

Attempt 1: Throwing exception
Caught exception: Something went wrong!
Attempt 2: Executing successfully
Total attempts made: 2

This confirms that the first failed execution didn't mark the flag as completed — the second call_once happily runs the working function.

Key Takeaways

  • std::call_once only considers the target function "done" when it executes fully without throwing.
  • Exceptions during execution reset the process: the flag stays untriggered, and future calls will retry.
  • You can't inspect the once_flag directly, but its behavior tells you everything you need to know about its state.

内容的提问来源于stack exchange,提问作者Thomas Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:09:53