可能并发写*相同*值到整数.我需要一个原子变量吗?

possible concurrent write of *same* value to an integer. Do I need an atomic variable?

本文关键字:一个 变量 相同 并发 整数      更新时间:2023-10-16

我想对一些遗留代码进行优化。优化可以归结为以下简单示例:

class Foo{
        static int m_count;   // allocated and initialized to -1 to indicate it's uninitialized.
        void fun(){
            if (m_count ==-1)
                m_count = execute_db_call(); // return a val > 0.
            if (m_count == 1) {
                 // call special == 1 optimized code.
            } else {
                 // call expensive code.
            }
       }
   }
  1. fun()将在数百个线程上被调用数百万次,所有这些线程都在256核服务器上并发运行。
  2. execute_db_call是昂贵的,返回值在应用程序的生命周期内是恒定的。

我需要或想要使m_count原子吗?在最坏的情况下,多个线程可能调用execute_db_call,并获得相同的值,然后将该值写入内存中的相同位置。即使两个线程都试图写相同的整数值,这是否是一个竞争条件?

如果我确实使成员原子化,我将为随后的只读行为带来什么样的性能开销?

Per standard§1.10/21:

如果一个程序在不同的线程中包含两个冲突的操作,且至少有一个不是原子操作,且两者都不先于另一个,则该程序的执行包含数据竞争。任何这样的数据竞争都会导致未定义的行为。

看起来你的代码符合这个定义,所以你会得到UB。现在,即使假设您的应用程序永远不会崩溃(哦,好吧……),您可能会得到不必要的execute_db_call调用,并且您已经明确声明"execute_db_call是昂贵的",所以它仍然很糟糕。

您没有说明在进程完成后需要确保m_count具有哪些属性(如果有的话),或者在处理过程的任何阶段它的值是否重要。在没有这些属性的情况下,还不如根本不给它赋值。如果您确实需要m_count的值在处理过程中的任何时候都不是未定义的,那么肯定必须使用同步来确保与该变量相关的操作顺序保持一致。

如果m_count只在-1的情况下写入,并且该变量由所有线程共享,那么将该初始化移到程序的并行部分之外会好得多。因此,您可以消除任何数据竞争,并避免不必要地调用昂贵的函数。