POD类型的保证原子操作自然与英特尔保持一致

问题描述 投票:0回答:1

我有一个在Intel Xeon 32内核上运行的C ++多线程应用程序,使用GCC 4.8.2编译并启用了优化。

我有多个线程(比如A,B,C)更新一些POD类型,另一个线程D每隔K秒读取这些变量并将其发送到GUI。线程产生在多个核心和套接字上。写操作受自旋锁保护。线程A,B,C对延迟敏感,其中高性能是关键方面。线程D对延迟敏感。

就像是:

Thread A,B,C
...
// a,b,c are up to 64 bits (let's say double)
spin-lock
a = computeValue();
b = computeValue();
c = computeValue();
spin-unlock
....

Thread D
...
// a,b,c are up to 64 bits (let's say double)
currValueA = a;
currValueB = b;
currValueC = c;
sendToGui(currValueA ,currValueB ,currValueC );
....

我想利用段落8.1.1 https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html,关于保证原子操作,并避免使用锁来保护线程D所做的读取。

我的理解是,如果a,b,c自然对齐(大小不超过64位),则线程D不会读取写入期间中途取得的a,b,c的值。换句话说,写入和读取将以原子方式执行。线程D将读取旧值或新值。

我的理解是否正确?

我留给编译器GCC 4.8.2来处理对齐,即我不使用任何gcc内置指令或函数,如std :: alignas,sts :: alignof等。

我知道代码不可移植。我宁愿不使用std :: atomic来避免任何不必要的开销。

c++ multithreading x86 atomic memory-alignment
1个回答
0
投票

读取“在写入期间中途取得”的值只是原子性的一个方面。

如今处理器将值保存在特定于处理器的缓存中,因此在多处理器系统上,两个不同的处理器可能具有不同的值,因为它们共享的a。将a标记为原子可确保不同的处理器看到“相同”的值。

此外,编译器和处理器通常对计算进行重新排序,以便更好地利用处理设施。这一切都没关系,只要这些计算的结果不会改变。 (这是C ++中的“似乎”规则)。但“未更改”是指在单个线程内执行。当多个线程冲击同一个对象时,在单个线程中工作的优化不一定有效。一般而言,您不希望您的单线程代码由不会执行常见优化的偏执编译器编译,因为它们可能会破坏多线程代码。相反,将对象标记为原子表示编译器应该非常小心它移动的内容,因为该对象的值可以在其他代码的后台更改。

因此,您可以选择:手动编写代码并希望您做到正确,或者接受atomic库的编写者可能更了解您所执行的目标系统上的原子性,并且可能会做得更好。

© www.soinside.com 2019 - 2024. All rights reserved.