Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

P.S: I cannot use locks.

like image 270
girijanandan nucha Avatar asked Jun 22 '17 06:06

girijanandan nucha


1 Answers

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. actomic operation (i.e. machine code command).

Out of the gcc doc. 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.

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:

/* 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).

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?. 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 (e.g. atomic_uint_least32_t).

like image 157
Scheff's Cat Avatar answered Sep 21 '22 01:09

Scheff's Cat