对于多线程应用程序中的显示任务,原子锁或互斥锁是必须的吗

Are atomics or mutex locks a must for display tasks in multi threading applications?

本文关键字:必须的 应用程序 多线程 任务 显示      更新时间:2023-10-16

我使用的是C++11和内置的线程类std::thread。使用std::atomicstd::mutex可以很容易地同步数据,但我想知道它是否真的有必要用于"非敏感"任务,同时维护一个无错误的应用程序。假设有一个类像

class FPS
{
  private:
    int rate;
  public:
    void change(const int i)
    {rate = i;}
    int read(void)
    {return rate;}
};

存储相机的帧速率。在应用程序中,有一个用于数据采集(帧抓取等)的线程读取帧速率,还有另一个线程处理显示帧速率的GUI。在这种情况下,显示是"非关键的",这意味着在某些情况下,允许显示滞后于实际速率。当然,我可以简单地使用原子来确保它的安全,但我仍然想知道,假设应用程序运行在多核CPU上,这是否真的是保证程序无缺陷性能的必要条件。

C++线程模型在代码运行时所做的部分是非常宽松的。您对C++的特定实现可能不会像C++允许的那样疯狂。

依赖它的问题是,如果没有记录和理解它,编译器的下一个迭代版本可能会做出不同的假设,符合C++,并破坏代码。

例如,如果您通过未同步的int进行通信,编译器可能会注意到无法在此线程中修改数据。如果能够证明这一点,则可以将int存储在本地寄存器中,并且忽略来自另一个线程的对int的任何更新

更重要的是,一段代码可以从寄存器中读取,另一段可以从内存中读取,并且可以有不同的值。更重要的是,对代码中变量的一次读取可能会变成两次读取,而这两次读取可能不一致:我们深陷于未定义行为的领域。

所以,不,一般来说这是不安全的。即使你的测试没有检测到任何问题,没有出现在测试中的线程问题也是非常常见的:测试几乎永远不足以证明你的线程代码是安全的。

它在您的特定编译器、编译器版本和编译器标志上可能是安全的。

http://en.cppreference.com/w/cpp/atomic/memory_order介绍了如何在不完全atomics的情况下完成。请注意,并不是所有的CPU都会以不同的方式对待这些情况,但有一些体系结构可以区分所有这些情况。我发现所有的内存顺序规则都有点令人困惑,因为我不习惯在它们都存在的系统上工作,但如果你真的需要性能,你可以考虑它

根据我对"性能备忘单"的阅读,原子操作目前是昂贵的,但不是非常昂贵(比如说,比指针指向不在缓存中的内存地址更便宜)。