UNIX Portable Atomic Operations

前端 未结 7 1355
生来不讨喜
生来不讨喜 2020-12-05 07:01

Is there a (POSIX-)portable way in C for atomic variable operations similar to a portable threading with pthread?

Atomic operations are operations like \"increment a

相关标签:
7条回答
  • 2020-12-05 07:23

    I don't think there is.

    One way of solving it, licenses permitting of course, would be to copy the relevant per-architecture implementations from e.g. the Linux kernel space. I haven't followed the evolution of those primitives closely, but I would guess that they are indeed primitives, i.e. don't depend upon other services or APIs in the kernel.

    0 讨论(0)
  • 2020-12-05 07:27

    AFAIK there are no cross-platform ways to do atomic operations. There may be a library out there but I don't know of. Its not particularly hard to roll your own, though.

    0 讨论(0)
  • 2020-12-05 07:30

    No, POSIX does not specify any portable lock-free/atomic operations. That's why they have pthreads.

    You're either going to have to use non-standard ways or stick with ptrheads for portability.

    0 讨论(0)
  • 2020-12-05 07:34

    C11 atomics minimal runnable example

    With the addition of threads in glibc 2.28, we can do both atomics and threading in pure C11.

    Example from: https://en.cppreference.com/w/c/language/atomic

    main.c

    #include <stdio.h>
    #include <threads.h>
    #include <stdatomic.h>
    
    atomic_int acnt;
    int cnt;
    
    int f(void* thr_data)
    {
        for(int n = 0; n < 1000; ++n) {
            ++cnt;
            ++acnt;
            // for this example, relaxed memory order is sufficient, e.g.
            // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
        }
        return 0;
    }
    
    int main(void)
    {
        thrd_t thr[10];
        for(int n = 0; n < 10; ++n)
            thrd_create(&thr[n], f, NULL);
        for(int n = 0; n < 10; ++n)
            thrd_join(thr[n], NULL);
    
        printf("The atomic counter is %u\n", acnt);
        printf("The non-atomic counter is %u\n", cnt);
    }
    

    Compile and run:

    gcc -std=c11 main.c -pthread
    ./a.out
    

    Possible output:

    The atomic counter is 10000
    The non-atomic counter is 8644
    

    The non-atomic counter is very likely to be smaller than the atomic one due to racy access across threads to the non atomic variable.

    A pthreads example can be found at: How do I start threads in plain C?

    Tested in Ubuntu 18.04 (glibc 2.27) by compiling glibc from source: Multiple glibc libraries on a single host Ubuntu 18.10 has glibc 2.28 so things should just work there.

    0 讨论(0)
  • 2020-12-05 07:35

    Since you asked for OS X:

    (and since cross platformity was raised in this thread.)

    OS X has functions OSAtomicAdd32() and friends. They are declared in "/usr/include/libkern/OSAtomic.h". See The Threading Programming guide, section "Using Atomic Operations".

    And for Windows, there is InterlockedIncrement() and friends (see MSDN).

    Together with the gcc builtins __sync_fetch_and_add() and friends (has been linked above), you should have something for every main desktop platform.

    Please note that I did not yet use them by myself, but maybe will do so in the next few days.

    0 讨论(0)
  • 2020-12-05 07:40

    For anyone who stumbles upon this in the future, C11 atomics are the best way to do this now - I believe they will be included in GCC 4.9.

    0 讨论(0)
提交回复
热议问题