【问题标题】:Can I use memory_order_relaxed for multiple threads modifying/reading an atomic boolean?我可以将 memory_order_relaxed 用于修改/读取原子布尔值的多个线程吗?
【发布时间】:2021-11-12 14:08:26
【问题描述】:

注意,这是对What are the options for safely modifying and reading a boolean across multiple threads and cpus?

的跟进

我有一些 C++ 代码大致包含这个逻辑:

class wrapper_info {
public:
        bool isConnected();
        void connectedHandler();
        void disconnectedHandler();
protected:
        std::atomic<bool> _connected;
}

void wrapper_info::connectedHandler() {
        _connected.store(true, std::memory_order_relaxed);
}

void wrapper_info::disconnectedHandler() {
        _connected.store(false, std::memory_order_relaxed);
}

bool wrapper_info::isConnected() {
        return _connected.load(std::memory_order_relaxed);
}

它们的调用方式如下:

线程 1、2、3isConnected()

线程 2:连接启动时connectedHandler()

线程 3 disconnectedHandler() 连接断开时。

使用 memory_order_relaxed 是否足够?我的理解是,当我想确保其他线程可以看到围绕它的其他操作时,我只需要像 memory_order_release 和 memory_order_acquire 这样的其他操作。但我只是在设置/读取一个值。 非常感谢。

【问题讨论】:

  • 只要没有其他操作依赖于处于预期状态的值,是的,您可以在此处使用宽松设置。虽然,证明起来可能很棘手,所以除非你的栅栏真的会影响性能(你多久经历一次重新连接周期?),顺序模型最容易理解和推理。
  • 通常你必须更深入地挖掘 - 为什么你要设置和读取这个值?例如,如果您正在测试它以查看某些全局资源是否可用,那么您需要一个屏障来确保您对资源的访问在测试之前不会被重新排序。这不是一个你可以孤立地回答的问题。
  • 另一方面,如果没有比赛,您将如何做到这一点?如果线程 1 测试 isConnected() 并继续对连接做一些事情,但线程 3 在线程 1 实际启动之前断开了对象,会发生什么?
  • 同意内特;您可能需要某种引用计数来确定当前有多少线程想要保持连接处于活动状态,而不是检查isConnected(),线程会增加该计数器。如果它以前为零,那么您必须确定断开连接是否正在进行或已经发生。 (或者嗯,即使这还不够;两个线程都可以尝试声明,而第二个线程可以看到 ref 计数从 1 变为 2,即使它早先为零。所以我想在开始断开连接之前,cmpxchg 它到-999 或 INT_MIN。)

标签: c++ multithreading atomic memory-barriers


【解决方案1】:

正如其他人已经提到的那样,这是一个非常糟糕的设计。即使强烈关注您的问题。这不足以使用 'memory_order_relaxed' !因为 'memory_order_relaxed' 指示不要进行必要的变量同步。代码在不同线程中可能有不同的值! 请改用“memory_order_acq_rel”。

【讨论】:

猜你喜欢
  • 2021-07-01
  • 2021-11-10
  • 1970-01-01
  • 2012-02-13
  • 1970-01-01
  • 2011-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多