How to do an atomic increment and fetch in C?

2019-01-20 09:27发布

问题:

I'm looking for a way to atomically increment a short, and then return that value. I need to do this both in kernel mode and in user mode, so it's in C, under Linux, on Intel 32bit architecture. Unfortunately, due to speed requirements, a mutex lock isn't going to be a good option.

Is there any other way to do this? At this point, it seems like the only option available is to inline some assembly. If that's the case, could someone point me towards the appropriate instructions?

回答1:

GCC supports atomic operations:

gcc atomics



回答2:

__atomic built-ins

As of GCC 4.8, __sync built-ins have been deprecated in favor of the __atomic built-ins: https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html

They implement the C++ memory model, and std::atomic uses them internally.

The following POSIX threads example fails consistently with ++ on x86-64, and always works with _atomic_fetch_add.

#include <assert.h>
#include <pthread.h>
#include <stdlib.h>

enum CONSTANTS {
    NUM_THREADS = 1000,
    NUM_ITERS = 1000
};

int global = 0;

void* main_thread(void *arg) {
    int i;
    for (i = 0; i < NUM_ITERS; ++i) {
        __atomic_fetch_add(&global, 1, __ATOMIC_SEQ_CST);
        /* This fails consistently. */
        /*global++*/;
    }
    return NULL;
}

int main() {
    int i;
    pthread_t threads[NUM_THREADS];
    for (i = 0; i < NUM_THREADS; ++i)
        pthread_create(&threads[i], NULL, main_thread, NULL);
    for (i = 0; i < NUM_THREADS; ++i)
        pthread_join(threads[i], NULL); 
    assert(global == NUM_THREADS * NUM_ITERS);
    return EXIT_SUCCESS;
}

C11 _Atomic

In 5.1, the above code works with:

_Atomic int global = 0;
global++;

But I think threads.h is not yet implemented to actually create the threads without POSIX.



标签: c linux x86 atomic