Как сделать атомарный прирост и извлечь в C? - PullRequest
9 голосов
/ 01 марта 2010

Я ищу способ атомарного увеличения короткого замыкания, а затем вернуть это значение. Мне нужно сделать это как в режиме ядра, так и в режиме пользователя, так что это в C, под Linux, на архитектуре Intel 32bit. К сожалению, из-за требований к скорости блокировка мьютекса не будет хорошим вариантом.

Есть ли другой способ сделать это? На данный момент кажется, что единственная доступная опция - это встроить некоторую сборку. Если это так, кто-то может указать мне на соответствующие инструкции?

Ответы [ 2 ]

8 голосов

GCC __atomic_* встроенные

Начиная с GCC 4.8, встроенные __sync устарели в пользу встроенных __atomic: https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html

Они реализуют модель памяти C ++, а std::atomic использует их внутренне.

В следующем примере потоков POSIX происходит сбой последовательно с ++ на x86-64 и всегда работает с _atomic_fetch_add.

main.c

#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(void) {
    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;
}

Скомпилируйте иrun:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out ./main.c -pthread
./main.out

Анализ разборки в: Как запустить потоки в простом C?

Протестировано в Ubuntu 18.10, GCC 8.2.0, glibc 2.28.

C11 _Atomic

В 5.1 приведенный выше код работает с:

_Atomic int global = 0;
global++;

И C11 threads.h был добавлен в glibc 2.28,который позволяет создавать потоки в чистом ANSI C без POSIX, минимальный пример запуска: Как запустить потоки в простом C?

7 голосов
/ 01 марта 2010

GCC поддерживает атомарные операции:

gcc atomics

...