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

如何使用std::atomic_bool或std::atomic_flag?相关线程安全问题咨询

多线程下std::atomic_bool的使用疑问解答

你在跨线程回调中用std::atomic_bool做控制标志,以下是针对你的四个疑问的解答:

1. 使用std::atomic_bool是否会出现死锁?还有其他需要注意的问题吗?

std::atomic_bool的读写操作都是无锁原子操作(主流平台均支持),不会引发死锁。需要注意的点:

  • 所有对该原子变量的访问必须是原子操作,不能通过取地址后强制转换为普通指针进行非原子读写;
  • 你代码中autoBackup里的“读标志+重置”是两个独立的原子操作,并非原子的复合操作。如果你的场景允许偶尔重复执行do stuff,当前逻辑没问题;但如果要求严格只触发一次,建议用原子成员函数(比如exchange)把这两步合并成一个原子操作;
  • 默认内存顺序是std::memory_order_seq_cst,这是最严格的全局顺序保证,对于简单标志场景完全够用,性能开销可以忽略。

2. 像普通变量一样使用std::atomic_bool是否正确?若不正确该如何操作?

大部分场景下直接赋值、读取是合法的——因为std::atomic_bool重载了operator=和operator bool(),这些操作本身就是原子的。但有个优化点:
如果你需要“读取当前值并原子重置”这类复合逻辑,不要拆分成两次操作,应该用原子成员函数实现。比如你autoBackup里的逻辑可以改成:

if (standbyResumeTimerDelayBool.exchange(false)) {
    // do stuff
}

exchange会原子地把变量设为false并返回旧值,这样能避免两个线程同时进入do stuff的情况,逻辑更严谨。

3. 是否应该改用std::atomic_flag?

完全没必要。std::atomic_flag是功能最受限的原子类型,仅支持test_and_set和clear操作,而且必须用ATOMIC_FLAG_INIT初始化,代码可读性差。std::atomic_bool的API更贴合布尔标志的使用场景,易用性和可读性都更好。只有在极端追求最小开销或必须保证绝对无锁(atomic_flag是C++标准唯一保证无锁的原子类型)的场景下,才需要考虑它。你的场景用std::atomic_bool是最优选择。

4. 在类成员列表中初始化standbyResumeTimerDelayBool未报错,是否正确?

正确。C++11及以后支持非静态成员的类内初始化,std::atomic_bool standbyResumeTimerDelayBool = false;这种写法是合法的,等效于在构造函数初始化列表中完成初始化(如果构造函数没有显式覆盖的话)。

另外提醒一下:你Worker类里的std::atomic_bool cancel;没有显式初始化,这会导致它的初始值不确定,建议改成std::atomic_bool cancel = false;,避免未定义行为。


附你提供的代码片段(修正了注释错误):

//some code omitted to keep things simple
//first callback function, this boolean flag is checked at one other point in the program
static ULONG Replicator::standbyResumeCallbackFunction(PVOID context, ULONG type, PVOID setting);
ULONG Replicator::standbyResumeCallbackFunction(PVOID context, ULONG type, PVOID setting)
{
    if (type == PBT_APMRESUMEAUTOMATIC)
    {
        Replicator* replicator = reinterpret_cast<Replicator*>(context);
        replicator->standbyResumeSetTimerDelayBool();
    }
}

//Replicator class members
void standbyResumeSetTimerDelayBool() { standbyResumeTimerDelayBool = true; }
std::atomic_bool standbyResumeTimerDelayBool = false;

//behavior modified here
void Replicator::autoBackup()
{
    if (standbyResumeTimerDelayBool)
    {
        standbyResumeTimerDelayBool = false;
        //do stuff
    }
}


//second callback function
static DWORD CALLBACK copyProgress(
             LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
             LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
             DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
             LPVOID data);

DWORD Worker::copyProgress(LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred, LARGE_INTEGER, LARGE_INTEGER, DWORD, DWORD, HANDLE, HANDLE, LPVOID data)
{
    Worker *worker = static_cast<Worker *>(data);

    if (worker->getStop())
        return PROGRESS_CANCEL;
}

//Worker class members
bool getStop() { return cancel; }
std::atomic_bool cancel;

//cancel is set to false when backup begins
void Worker::startBackup()
{
    cancel = false;
}
//if user clicks cancel button cancel flag is set to true
void stop() { cancel = true; }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:44:57