将这些原子操作与宽松的内存顺序和rel / acq一起使用,如图所示,此C ++代码段有效吗?

时间:2019-05-05 08:42:35

标签: c++ c++11 atomic memory-model compare-and-swap

用cppmem伪代码编写:

int main()                                                                                                                                                                                   
{                                                                                                                                                                                            
  atomic_int n = -1;                                                                                                                                                                         
  atomic_int n2 = 0;                                                                                                                                                                         

  {{{                                                                                                                                                                                        
      {                                                                                                                                                                                      
        n2.store(1, mo_relaxed);                                                                                                                                                             
        if (n.load(mo_relaxed) != -1)                                                                                                                                                        
          n.store(1, mo_release);                                                                                                                                                            
      }                                                                                                                                                                                      
  |||                                                                                                                                                                                        
      {                                                                                                                                                                                      
        n.store(0, mo_release);                                                                                                                                                              
        int expected = 0;                                                                                                                                                                    
        do                                                                                                                                                                                   
        {                                                                                                                                                                                    
          desired = n2.load(mo_relaxed);                                                                                                                                                     
        }                                                                                                                                                                                    
        while (!n.compare_exchange_strong(&expected, desired, mo_acquire));                                                                                                                  
      }                                                                                                                                                                                      
  }}}                                                                                                                                                                                        

  assert(n == 1);                                                                                                                                                                            
}                                                                                                                                                                                            

换句话说,两个原子变量被初始化为n = -1和n2 = 0;

线程1首先将1写入n2,然后写入n,前提是n不(仍然)-1。

线程2首先将0写入n,然后加载n2并分配n = n2,前提是自从上次读取n(或当n仍为0以来)不改变n为止。

在两个线程都加入后,n在每个可能的执行中必须等于1。

此代码是我的一个开源项目的一部分,与将streambuf实现重置为无锁缓冲区的开始同时两个线程同时对其进行读写操作有关。该特定部分与“同步”(或刷新写入的输出)有关。

我对此进行了设计,并且在每个操作都相继一致时(通过了蛮力测试)它可以工作,但是我无法满足内存顺序要求:/。

2 个答案:

答案 0 :(得分:1)

如果按以下顺序执行指令(和缓存更新),则可能触发此断言:

  • 第一个线程运行所有指令。因此,只需将n2的值从0更改为1
  • 然后线程2运行。首先,它将n的值从-1更改为0
  • 然后线程2加载n2(在n2.load(mo_relaxed)中)。此时,由于没有同步,因此可以加载先前存储在n2中的任何值(包括初始化值,请参见[intro.race]/1)。假设它加载了0
  • 因此线程2的变量值是比较之前的n==0(修改顺序为n的最后一个),n2==0expected==0desired==0交换指令。然后,比较交换成功,并将0存储在n中。

两个线程执行结束时,您将得到n==0n2==1

具有顺序一致性,因为线程1看到了n2==1 && n==-1,线程2看不到n2==0 && n==0,所以我无法描述。

使用这种算法,我确信除了顺序一致性之外,无法使用其他任何内存顺序。

答案 1 :(得分:0)

使用我在https://plv.mpi-sws.org/rcmc/上找到的工具 通过实验,我发现最宽松的要求是:

线程1:

n2.store(1, std::memory_order_seq_cst);
if (n.load(std::memory_order_seq_cst) != -1)
  n.store(1, std::memory_order_release);

线程2:

n.store(0, std::memory_order_seq_cst);
int expected = 0;
int desired;
do
{
    desired = n2.load(std::memory_order_seq_cst);
}
while (!n.compare_exchange_strong(expected, desired,
    std::memory_order_acquire, std::memory_order_relaxed));

编辑:

同一作者的最新工具(当然也更好) 现在可以从https://github.com/MPI-SWS/genmc

下载

即使对于测试使用弱序原子的实时算法,该工具也非常快速且有用,例如,我在这里进行的操作:genmc_buffer_reset_test.c

给定行上的#include是生成的C文件,这些文件从我的C ++代码中提取并使用awk脚本转换为C,因为在我看来genmc只能(不幸地)仅用于C代码(?)。 / p>