gccthread-safetyvolatileatomicreference

GCC atomic builtins and volatile


I use some global structures in a multithreaded program, some of the members are modified by multiple threads simultaneously, some others are not.

I didn't define any of this members volatile, but anytime i use this members for both reading and writing purposes, i use atomic builtins such as __sync_fetch_and_add.

The question is, should i define this members or the whole struct volatile?

I think the compiler has to access the memory instead any register because of this builtins (lock prefix), should i be worried about other members that are not cause race conditions.

I checked out the assembly output of my compiler (gcc 4.6.2) and it seems my assumption is right.

Here is the test code.

int sum = 0;

for (i=0; i<2000000000; i++) {
    sum += i;
}

The assembly output (-O2 -S -masm=intel)

L2:
    add edx, eax
    inc eax
    cmp eax, 2000000000
    jne L2

So compiler is never accessed the memory (eax = i, edx = sum)

Here is the second test code.

volatile int sum = 0;

for (i=0; i<2000000000; i++) {
    sum += i;
}

The assembly output

L2:
    mov edx, DWORD PTR [esp+28]
    add edx, eax
    mov DWORD PTR [esp+28], edx
    inc eax
    cmp eax, 2000000000
    jne L2

Compiler accessed the memory for sum everytime as expected.

The final code, my way.

int sum = 0;

for (i=0; i<2000000000; i++) {
    __sync_fetch_and_add(&sum , i);
}

The assembly output.

L2:
    lock add    DWORD PTR [esp+28], eax
    inc eax
    cmp eax, 2000000000
    jne L2

Not even a temp register as before (edx), compiler accessed the memory everytime.

So, i don't define volatile any member that modified by multiple threads or modified by only one thread at a time. Am i safe?

Thanks in advance.


Solution

  • Yes, you are safe. The documentation does not say they should be volatile, so they shouldn't.

    The __sync* functions act as memory barriers as appropriate, so volatile would be superfluous. And it wouldn't allow using anything else beyond the __sync* functions anyway (only the __sync* functions generate the lock prefix).

    Note: The __sync* functions are deprecated in gcc 4.7 in favour of C++11-style __atomic* types, but gcc 4.6 does not have those yet.