Переносные атомные операции UNIX
Есть ли (POSIX-) переносимый способ в C для операций с атомной переменной, аналогичный переносимой потоковой передаче с pthread?
Атомные операции - это операции, такие как "increment and get", которые выполняются атомарно, что означает, что контекстный переключатель не может помешать операции. В пространстве ядра Linux мы должны atomic_t, в Java у нас есть java.util.concurrent.atomic.
В Linux файл atomic.h содержит атомарные операции, но включение зависит от платформы, например. #include <asm-x86_64/atomic.h>
, и он недоступен в Mac OS X аналогичным образом.
Ответы
Ответ 1
Начиная с C11 существует дополнительная атомарная библиотека, которая обеспечивает атомарные операции. Это переносимо на любую платформу с компилятором C11 (например, gcc-4.9) с этой дополнительной функцией.
Присутствие атомарного можно проверить с помощью __STDC_NO_ATOMICS__
и наличие <stdatomic.h>
atomic.c
#include <stdio.h>
#include <stdlib.h>
#ifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#endif
int main(int argc, char**argv) {
_Atomic int a;
atomic_init(&a, 42);
atomic_store(&a, 5);
int b = atomic_load(&a);
printf("b = %i\n", b);
return EXIT_SUCCESS;
}
Вызовы компилятора
clang -std=c11 atomic.c
gcc -std=c11 atomic.c
Ответ 2
Для тех, кто наткнется на это в будущем, C11 atomics - лучший способ сделать это сейчас - я считаю, что они будут включены в GCC 4.9.
Ответ 3
Поскольку вы попросили OS X:
(а так как в этом потоке поднята кросс-платформа).
OS X имеет функции OSAtomicAdd32() и друзья. Они объявлены в "/usr/include/libkern/OSAtomic.h".
См. Руководство по программированию Threading, раздел "Использование атомных операций".
А для Windows есть InterlockedIncrement() и друзья (см. MSDN).
Вместе с gcc builtins __ sync_fetch_and_add() и друзьями (был указан выше), вы должны иметь
что-то для каждой основной настольной платформы.
Обратите внимание, что я еще не использовал их самостоятельно, но, возможно, сделаю это в ближайшие несколько дней.
Ответ 4
Нет, POSIX не указывает никаких переносных операций блокировки/атома. Вот почему у них есть pthreads.
Вам либо придется использовать нестандартные способы, либо придерживаться ptrheads для переносимости.
Ответ 5
C11 атомный минимальный работоспособный пример
С добавлением потоков в glibc 2.28 мы можем выполнять как атомарность, так и создание потоков в чистом C11.
Пример из: 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);
}
Скомпилируйте и запустите:
gcc -std=c11 main.c -pthread
./a.out
Возможный вывод:
The atomic counter is 10000
The non-atomic counter is 8644
Неатомарный счетчик, скорее всего, будет меньше атомного из-за быстрого доступа через потоки к неатомарной переменной.
Пример pthreads можно найти по адресу: Как запустить потоки в простом C?
Протестировано в Ubuntu 18.04 (glibc 2.27) путем компиляции glibc из исходного кода: несколько библиотек glibc на одном хосте Ubuntu 18.10 имеет glibc 2.28, поэтому все должно работать просто так.
Ответ 6
AFAIK нет кросс-платформенных способов выполнения атомных операций. Там может быть библиотека, но я не знаю. Тем не менее, это не особенно сложно катить.
Ответ 7
Я не думаю, что есть.
Одним из способов его решения, конечно же, разрешениями на лицензии было бы копирование соответствующих реализаций каждой архитектуры из, например, ядро Linux. Я не очень внимательно следил за эволюцией этих примитивов, но я бы предположил, что они действительно примитивы, т.е. Не зависят от других сервисов или API в ядре.