The __sync_fetch_and_add function is a built-in atomic operation provided by GCC and Clang for performing atomic addition on a variable. It ensures that the operation is thread-safe, which is essential for concurrent programming.

Here's a simple example in C:

#include <stdio.h>
#include <stdatomic.h>
#include <pthread.h>

// Shared variable
atomic_int counter = 0;

// Thread function
void* increment_counter(void* arg) {
    for (int i = 0; i < 1000; ++i) {
        // Atomically add 1 to counter and fetch the old value
        int old_value = __sync_fetch_and_add(&counter, 1);
        // Print the old value
        printf("Thread %ld: Old value = %d\n", (long)pthread_self(), old_value);
    }
    return NULL;
}

int main() {
    pthread_t threads[10];
    
    // Create threads
    for (int i = 0; i < 10; ++i) {
        pthread_create(&threads[i], NULL, increment_counter, NULL);
    }
    
    // Join threads
    for (int i = 0; i < 10; ++i) {
        pthread_join(threads[i], NULL);
    }
    
    printf("Final counter value: %d\n", counter);
    return 0;
}

Explanation:

  1. Atomic Variable Declaration: atomic_int counter = 0; declares an atomic integer variable that is safe to use across multiple threads.
  2. Thread Function: increment_counter function uses __sync_fetch_and_add to atomically add 1 to the counter and returns the old value. This function is executed by multiple threads.
  3. Thread Creation and Joining: In main, ten threads are created and each runs increment_counter. After all threads are created, the main function waits for them to finish by calling pthread_join.
  4. Output: Each thread prints the old value of the counter before incrementing it. Finally, the main function prints the final value of the counter.

Notes:

  • __sync_fetch_and_add: This built-in function is used to perform an atomic addition. It adds a given value to a variable and returns the old value of the variable.
  • Atomic Operations: They are crucial in multi-threaded programs to prevent race conditions and ensure that operations on shared variables are performed safely.

This example demonstrates the use of atomic operations to manage shared state across multiple threads efficiently.