原子操作 - C

Atomic operations - C

是否可以让两个变量自动递增。我有以下代码,因为它是一个多处理器、多线程环境,缓存失效成为性能瓶颈。所以,我试图尽量减少原子操作的数量。

__sync_add_and_fetch(&var1,1);
__sync_add_and_fetch(&var2,1);

我看到第一个参数是一个指针,是否可以使用结构来实现我的情况?

P.S: 我不能使用锁。

原子操作非常特殊,只提供有限的支持。将它们应用于两个变量对我来说听起来是不可能的。

请注意,甚至不能保证原子操作真的是用 resp 完成的。原子操作(即机器代码命令)。

在 gcc 文档之外。 5.47 Built-in functions for atomic memory access:

Not all operations are supported by all target processors. If a particular operation cannot be implemented on the target processor, a warning will be generated and a call an external function will be generated. The external function will carry the same name as the builtin, with an additional suffix '_n' where n is the size of the data type.

外部函数可能使用互斥体模拟原子操作。

但我想,使用 "dirty hack" 是可能的,但有一定的限制:

如果 16 位无符号计数器就足够了,您可以将其中两个放在一个 32 位变量中,其中 c1c2 += 0x00000001 递增一个,c1c2 += 0x00010000 递增另一个,c1c2 += 0x00010001 递增两个 或使用原子操作:

/* combined counters c1 and c2 */
static uint32_t c1c2 = 0;

/* count c1 atomically */
__sync_fetch_and_add(&c1c2, 0x00000001);
/* count c2 atomically */
__sync_fetch_and_add(&c1c2, 0x00010000);
/* count c1 AND c2 atomically */
__sync_fetch_and_add(&c1c2, 0x00010001);

这必须与适当的位移位和掩码相结合才能访问单个计数器值。

当然,计数器溢出可能是个问题。这同样适用于 64 位平台上的两个 32 位计数器(考虑到原子操作通常仅适用于 "machine word" 宽度)。

顺便说一句。在谷歌搜索背景信息时,我偶然发现了这个:Why does __sync_add_and_fetch work for a 64 bit variable on a 32 bit system?。我发现原子操作可能需要足够的变量对齐才能正常工作的提示(我发现值得一提)。

这可能是 C11 Atomic Library 为原子变量(例如 atomic_uint_least32_t)提供专用类型的原因。

除了两个 Pentium(2001 年的 AMD 处理器或其他处理器)之外的所有处理器都支持 128 位原子操作。那是 16 个字节。

通过 atomic<> 模板在 C++ 中提供对这些操作的支持,尽管最近的 GCC 版本之一已将此功能关闭以用于 16 字节值并使用锁代替。然而,个别编译器有办法访问这些,原则上你也可以用机器语言编写它。

操作范围有限,但原则上可以在常规C中为所欲为,然后通过CAS操作将已有内容替换为新内容。 CAS 只是意味着:CPU,将值 A 写入内存位置 B,当且仅当 B 当前持有值 C。所以:读取值;做你的数学;然后使用 CAS 并在成功时使用 CAS 成功代码打破 do..while 循环。