当前位置: 首页 > 知识库问答 >
问题:

Std::Atomic::Load的内存排序行为

钱承允
2023-03-14
volatile bool arm1 = false;
std::atomic_bool arm2 = false;
bool triggered = false;
arm1 = true;
//std::std::atomic_thread_fence(std::memory_order_seq_cst); // this would do the trick 
if (arm2.load())
    triggered = true;
arm2.store(true);
if (arm1)
    triggered = true;

虽然我不得不承认,我并不完全理解内存顺序的不同松弛语义的正式定义,但我认为顺序一致的顺序非常简单,因为它保证了“存在一个单一的总顺序,其中所有线程都以相同的顺序观察所有修改”。对我来说,这意味着用默认内存顺序STD::MEMORY_ORDER_SEQ_CST加载STD::Atomic::还可以充当内存栅栏。“顺序一致的排序”下的以下陈述进一步证实了这一点:

在所有多核系统上,完全顺序排序需要一个完整的内存栅栏CPU指令。

然而,我下面的简单示例演示了MSVC2013、GCC4.9(x86)和CLANG3.5.1(x86)不是这种情况,在这些情况下,原子加载只是转换为加载指令。

#include <atomic>

std::atomic_long al;

#ifdef _WIN32
__declspec(noinline)
#else
__attribute__((noinline))
#endif
long load() {
    return al.load(std::memory_order_seq_cst);
}

int main(int argc, char* argv[]) {
    long r = load();
}
load():
   mov  rax, QWORD PTR al[rip]   ; <--- plain load here, no fence or xchg
   ret
main:
   call load()
   xor  eax, eax
   ret
load():
     dmb    sy                         ; <---- data memory barrier here
     movw   r3, #:lower16:.LANCHOR0
     movt   r3, #:upper16:.LANCHOR0
     ldr    r0, [r3]                   
     dmb    sy                         ; <----- and here
     bx lr
main:
    push    {r3, lr}
    bl  load()
    movs    r0, #0
    pop {r3, pc}

这不是一个学术问题,它在代码中导致了一个微妙的竞争条件,这使我对STD::Atomic行为的理解受到质疑。

共有1个答案

澹台正业
2023-03-14

叹息,这太长了,不能评论:

原子的意义不是“对系统的其余部分来说似乎是瞬间发生的”吗?

我会对那件事说是或不是,这取决于你如何看待它。对于使用seq_cst写入,是。但是关于原子负载是如何处理的,请参阅C++11标准的29.3。具体来说,29.3.3确实是很好的阅读,而29.3.4可能正是您要寻找的内容:

 类似资料:
  • 我不知道如何创建以下内容: 我总是得到 /usr/include/c/5.5.0/bits/stl_对。h:139:45:错误:使用已删除的函数'std::atomic::atomic(const std::atomic 我已经试过了 我知道std::atomic是不可复制的,那么你应该如何创建一对呢?难道这不可能吗?

  • 我知道是一个原子对象。但是原子化到什么程度呢?据我所知,操作可以是原子的。使一个对象原子化到底是什么意思?例如,如果有两个线程同时执行以下代码: 那么整个操作(例如)是原子操作吗?还是对变量atomic(so)进行了更改?

  • 我在std::sort中发现了一个bug,特别是在一些QuickSort的实现中,我不知道问题是否出在一般的算法中。 精华: 当元素小于16时,所有的规范都被替换,因为std::sort使用插入排序。 当有17个或更多的元素时,使用快速排序,并从元素数量的对数限制递归深度,但向量在第一次__introsort_loop迭代时有时间恶化。 当有许多相同的元素时,就会出现向量损坏。用无效迭代器替换有效

  • Item 40: 当需要并发时使用std::atomic,特定内存才使用volatile 可伶的volatile。如此令人迷惑。本不应该出现在本章节,因为它没有关于并发的能力。但是在其他编程语言中(比如,Java和C#),volatile是有并发含义的,即使在C++中,有些编译器在实现时也将并发的某种含义加入到了volatile关键字中。因此在此值得讨论下关于volatile关键字的含义以消除异议

  • 来自C++20的的行为是否类似于互斥/原子操作?即是获取操作(关于内存排序)吗,是释放操作吗?

  • 我有一个关于使用数字列表构建金字塔的任务,但是有一个测试有一个问题。在我的任务中,我需要对列表进行排序。我使用Collections.sort(): 但此测试失败 使用内存错误而不是我自己的无法构建金字塔例外(排序后将以另一种方法抛出)。我知道这是因为蒂姆索特在收集.sort()方法。我试图使用堆排序,但我甚至无法交换元素,因为我的输入列表被初始化为 Arrays.asList(),当我使用 se