原子操作 - C.

时间:2017-06-22 06:07:40

标签: c multithreading concurrency atomic

是否可以原子地递增两个变量。我有以下代码,因为它是一个多处理器,多线程环境,缓存失效成为性能瓶颈。所以,我正在努力减少原子操作的数量。

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

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

P.S:我不能使用锁。

2 个答案:

答案 0 :(得分:3)

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

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

出了gcc doc。 5.47 Built-in functions for atomic memory access

  

并非所有目标处理器都支持所有操作。如果无法在目标处理器上实现特定操作,则将生成警告并将生成调用外部函数。外部函数将使用与内置函数相同的名称,并附加后缀' _n'其中n是数据类型的大小。

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

但是我想,这可能是一个"肮脏的黑客"并且只有一定的限制:

如果16位无符号计数器就足够了,你可以将其中两个置于一个32位变量中,其中c1c2 += 0x00000001递增1,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位计数器(考虑到原子操作通常仅适用于"机器字"宽度)。

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

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

答案 1 :(得分:0)

除两个奔腾(2001或更高版本的AMD处理器)外,所有奔腾均支持128位原子操作。那是16个字节。

通过原子<>模板可以在C ++中获得对这些操作的支持,尽管最近的GCC版本之一已将此功能关闭为16字节值,而是使用了锁定。但是,各个编译器都可以访问这些方法,原则上您也可以用机器语言编写。

操作范围是有限的,但是原则上您可以在常规C中做任何您想做的事,然后用CAS操作用新内容替换现有内容。 CAS仅表示:CPU,如果且仅当B当前持有值C时,才将值A写入内存位置B。做你的数学;然后使用CAS并使用CAS成功代码在成功时中断do..while循环。