相关疑难解决方法(0)

忙等待循环中是否需要内存屏障或原子操作?

考虑以下spin_lock()实现,最初来自这个答案:

void spin_lock(volatile bool* lock)  {  
    for (;;) {
        // inserts an acquire memory barrier and a compiler barrier
        if (!__atomic_test_and_set(lock, __ATOMIC_ACQUIRE))
            return;

        while (*lock)  // no barriers; is it OK?
            cpu_relax();
    }
}
Run Code Online (Sandbox Code Playgroud)

我所知道的:

  • volatile防止编译器*lockwhile循环的每次迭代中优化重新读取;
  • volatile 不插入内存或编译器障碍 ;
  • 这样的实现实际上可以在GCC中工作x86(例如在Linux内核中)和其他一些架构;
  • 至少一个存储器和编译器屏障需要spin_lock()执行针对通用体系结构; 这个例子插入它们__atomic_test_and_set().

问题:

  1. volatile这里是否足够或者是否存在while循环中需要内存或编译器障碍或原子操作的架构或编译器?

    1.1根据C++标准?

    1.2在实践中,对于已知的体系结构和编译器,特别是它支持的GCC和平台?

  2. 在GCC和Linux支持的所有体系结构上,此实现是否安全?(在某些架构上至少效率低下,对吧?)
  3. while根据C++11它的内存模型,循环是否安全?

有几个相关的问题,但我无法从它们构建一个明确和明确的答案:

  • 问:单线程中的内存障碍

    原则上:是的,如果程序执行从一个核心移动到下一个核心,则可能看不到在先前核心上发生的所有写入. …

c++ multithreading gcc spinlock memory-barriers

21
推荐指数
3
解决办法
1924
查看次数

C++20 内存模型中释放序列定义的更改有何影响?

考虑这个程序:

-- Initially --
std::atomic<int> x{0};
int y{0};
    
-- Thread 1 --
y = 1;                                      // A
x.store(1, std::memory_order_release);      // B
x.store(3, std::memory_order_relaxed);      // C

-- Thread 2 --
if (x.load(std::memory_order_acquire) == 3) // D
    print(y);                               // E
Run Code Online (Sandbox Code Playgroud)

在 C++11 内存模型下,如果程序打印任何内容,则它会打印 1

在 C++20 内存模型中,释放顺序已更改以排除由同一线程执行的写入。这对这个程序有何影响?现在可以进行数据竞争并打印 或01

笔记

这段代码出现在P0982R1: Weaken Release Sequences中,我相信这篇论文导致了 C++20 中发布序列定义的更改。在该特定示例中,有第三个线程进行存储,x该存储以违反直觉的方式中断了释放顺序。这激发了削弱发布顺序定义的需要。

通过阅读该论文,我的理解是,随着C++20的变化,C将不再构成以B为首的发布序列的一部分,因为C不是读-修改-写操作。因此C不与D同步。因此A和E之间不存在happens-before关系。

由于 B 和 C 存储到同一个原子变量,并且所有线程必须就该变量的修改顺序达成一致,因此 C++20 内存模型是否允许我们推断 A 是否发生在 E 之前?

c++ concurrency atomic memory-model c++20

5
推荐指数
1
解决办法
157
查看次数

是否会在其他线程中始终以相同顺序看到对不同线程中不同位置的两次原子写操作?

与我之前的问题类似,请考虑以下代码

-- Initially --
std::atomic<int> x{0};
std::atomic<int> y{0};

-- Thread 1 --
x.store(1, std::memory_order_release);

-- Thread 2 --
y.store(2, std::memory_order_release);

-- Thread 3 --
int r1 = x.load(std::memory_order_acquire);   // x first
int r2 = y.load(std::memory_order_acquire);

-- Thread 4 --
int r3 = y.load(std::memory_order_acquire);   // y first
int r4 = x.load(std::memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)

怪异的结果 r1==1, r2==0,并r3==2, r4==0有可能在C ++ 11内存模型下,这种情况下?如果我要全部替换std::memory_order_acq_rel成该std::memory_order_relaxed怎么办?

在x86上,这样的结果似乎是被禁止的,请参见此SO问题,但我一般是在询问C ++ 11内存模型。

奖励问题:

我们都同意,与std::memory_order_seq_cst怪异的结果不会在C ++ 11被允许。现在,赫伯·萨特(Herb Sutter)在他著名的- …

c++ concurrency memory-model c++11 stdatomic

4
推荐指数
3
解决办法
540
查看次数