简体   繁体   English

原子操作-C

[英]Atomic operations - C

Is it possible to have two variables incremented atomically.是否可以让两个变量以原子方式递增。 I have the following code and since it's a multi-processor, multi-threaded environment, cache invalidations becomes a performance bottleneck.我有以下代码,由于它是一个多处理器、多线程环境,缓存失效成为性能瓶颈。 So, I am trying to minimise the number of atomic operations.所以,我试图尽量减少原子操作的数量。

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

I see that the first argument is a pointer, is it possible to achieve my case by using a structure?我看到第一个参数是一个指针,是否可以通过使用结构来实现我的情况?

PS: I cannot use locks. PS:我不能使用锁。

Atomic operations are very special and provide only limited support.原子操作非常特殊,只能提供有限的支持。 Applying them to two variables sounds impossible for me.将它们应用于两个变量对我来说听起来是不可能的。

Note, that it is even not garanteed that an atomic operation is really done with a resp.请注意,甚至不能保证原子操作确实是通过 resp 完成的。 actomic operation (ie machine code command).原子操作(即机器代码命令)。

Out of the gcc doc.出 gcc 文档。 5.47 Built-in functions for atomic memory access : 5.47 原子内存访问的内置函数

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.外部函数将带有与内置函数相同的名称,并带有一个附加后缀“_n”,其中 n 是数据类型的大小。

The external function probably emulates the atomic operation using a mutex.外部函数可能使用互斥锁模拟原子操作。

But I guess, it would be possible with a "dirty hack" and only with certain limitations:但我想,“肮脏的黑客”是可能的,并且只有某些限制:

If 16 bit unsigned counters are sufficient, you could put two of them in one 32 bit variable where c1c2 += 0x00000001 increments one, c1c2 += 0x00010000 increments the other, and c1c2 += 0x00010001 increments both or using the atomic operations:如果 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);

This has to be combined with the appropriate bit shifting and masking to access the invidiual counter values.这必须与适当的位移位和屏蔽相结合才能访问各个计数器值。

Of course, counter overflow could be an issue.当然,计数器溢出可能是一个问题。 The same might work for two 32 bit counters on a 64 bit platform (considering that atomic operations are usually only available for "machine word" width).这同样适用于 64 位平台上的两个 32 位计数器(考虑到原子操作通常仅适用于“机器字”宽度)。

Btw.顺便说一句。 while googling for background info, I stumbled over this: Why does __sync_add_and_fetch work for a 64 bit variable on a 32 bit system?在谷歌搜索背景信息时,我偶然发现了这一点: 为什么 __sync_add_and_fetch 在 32 位系统上适用于 64 位变量? . . I found the hint that atomic operations may require sufficient alignment of variables to work properly (which I found worth to mention).我发现原子操作可能需要足够的变量对齐才能正常工作的提示(我发现值得一提)。

This might be the reason why the C11 Atomic Library provides dedicated types for atomic variables (eg atomic_uint_least32_t ).这可能是C11 原子库为原子变量提供专用类型的原因(例如atomic_uint_least32_t )。

All but two Pentiums (AMD processors from like 2001, or something) support 128-bit atomic operations.除了两个 Pentium(来自 2001 年的 AMD 处理器或其他处理器)之外,所有处理器都支持 128 位原子操作。 That's 16 bytes.那是 16 个字节。

Support for these operations is available in C++ via the atomic<> template, though one of the recent GCC versions had this turned off for 16-byte values and used a lock instead.通过 atomic<> 模板在 C++ 中提供对这些操作的支持,尽管最近的 GCC 版本之一为 16 字节值关闭了此功能并改为使用锁。 However individual compilers have ways to access these and you can in principle write it in machine language as well.然而,个别编译器有办法访问这些,原则上你也可以用机器语言编写它。

The range of operations is limited, but you can in principle do whatever you want in regular C, and then replace the existing contents with new contents with a CAS operation.操作的范围是有限的,但原则上你可以在常规 C 中做任何你想做的事情,然后用 CAS 操作将现有内容替换为新内容。 CAS just means: CPU, write value A into memory location B, if and only if B currently holds value C. So: read the values; CAS 只是意味着:CPU,将值 A 写入内存位置 B,当且仅当 B 当前持有值 C。所以:读取值; do your math;做你的数学; then use CAS and use the CAS success code to break a do..while loop when it succeeds.然后使用 CAS 并使用 CAS 成功代码在成功时中断 do..while 循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM