【问题标题】:In a multi-threaded C++ app, do I need a mutex to protect a simple boolean?在多线程 C++ 应用程序中,我是否需要互斥锁来保护简单的布尔值?
【发布时间】:2023-03-07 05:29:01
【问题描述】:

我有一个多线程 C++ 应用程序,它使用 OpenSceneGraph 库进行 3D 渲染。我计划使用 boost::threads 将 OSG 的渲染循环作为一个单独的线程启动,将包含共享状态的数据结构传递给线程。我试图避免任何过于重量级的东西(如互斥锁)进行同步,因为渲染循环需要非常紧凑,而 OSG 本身试图避免必须锁定。大多数共享状态是在线程启动之前设置的,并且永远不会改变。我确实有一些需要更改的数据,我计划对其进行双重缓冲。但是,我有一个简单的布尔值,用于指示线程暂停渲染,然后恢复渲染,以及另一个来终止它。在这两种情况下,应用程序线程都会设置布尔值,而渲染线程只读取它。我需要同步对这些布尔值的访问吗?据我所知,可能发生的更糟糕的事情是渲染循环会在暂停或退出之前继续进行额外的帧。

【问题讨论】:

    标签: c++ multithreading boolean mutex openscenegraph


    【解决方案1】:

    在具有标准定义并发的 C++11 及更高版本中,为此目的使用 std::atomic<bool>。来自http://en.cppreference.com/w/cpp/atomic/atomic

    如果一个线程写入一个原子对象而另一个线程从它读取,则行为是明确定义的(有关数据竞争的详细信息,请参阅内存模型)。


    对于某些编译器和某些操作环境,以下旧答案在过去的某个时候可能是正确的,但今天不应该依赖它:

    你是对的,在这种情况下你不需要同步布尔值。不过,您应该声明它们volatile,以确保编译器实际上每次都从内存中读取它们,而不是在线程中缓存先前的读取(这是一个简化的解释,但它应该为此目的)。

    以下问题对此有更多信息: C++ Thread, shared data

    【讨论】:

    • 不过,规范中的“易失性”实际上并不是这样做的。 MSVC 对懒惰的程序员更宽容一些,但 GCC 肯定会很乐意优化、重新安排或以其他方式破坏您的“易失性”内存访问。
    • IIRC,根据规范,'volatile' 意味着编译器必须假定变量可以在应用程序控制之外的任何时间更改。因此,如果编译器是正确的,'volatile' 应该会产生预期的效果。
    • 这是对的,但没用。对 volatile 对象的访问必须已经过评估,但是 C++ 对来自另一个线程的写入是否对您的线程可见,没有什么可说的,因为 C++ 对线程没有什么可说的。您必须查阅您的编译器/线程文档,或使用 C++0x。
    • 例如,C++ 规范确实要求在具有非一致缓存的系统上,易失性访问会导致缓存同步,只是访问(缓存)不是t 移动了一个序列点。编译器可能很友好,并且对易失性访问进行缓存同步。也可能不会。
    • volatile 不会阻止读/写重新排序。 VC++ 2005/8 似乎正确地做到了这一点,它以与 Java 5 相同的方式为关键字 volatile 添加了额外的含义。另一方面,GCC 肯定会重新排序。
    【解决方案2】:

    为什么不直接使用interlocked variable

    【讨论】:

    • 使用这些没有开销吗?
    • 那么这就是为什么最好使用纯布尔值,它更简单更快。
    【解决方案3】:

    对于 C++11 及更高版本,它最终是线程感知的,并明确指出在一个线程中修改 bool(或其他非原子变量)并在另一个线程中同时访问它是未定义的行为。 在您的情况下,使用 std::atomic<bool> 应该足以使您的程序正确,从而避免使用锁。
    不要使用 volatile。它与线程无关。 更多讨论请查看Can I read a bool variable in a thread without mutex?

    【讨论】:

      【解决方案4】:

      我不认为你在这里需要一个完全成熟的互斥锁 - 尽管如果你不使用支持的同步对象,渲染线程将需要在“暂停”状态下忙于等待等待原语。

      您应该考虑使用各种互锁交换原语(Windows 下的 InterlockedExchange)。不是因为从 bool 读取/写入是非原子的,而是为了确保没有奇怪的行为,编译器在单个线程上重新排序内存访问。

      【讨论】:

        【解决方案5】:

        这个线程有更多关于线程安全的信息和讨论,特别是对于简单的数据类型:

        How can I create a thread-safe singleton pattern in Windows?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-25
          • 2012-05-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-11
          相关资源
          最近更新 更多