Функции для выполнения атомарных операций
существуют ли функции для выполнения атомарных операций (например, инкремент / декремент целого числа) и т. д., поддерживаемые библиотекой времени выполнения C или любыми другими библиотеками утилит?
Если да, то какие все операции можно сделать атомарными с использованием таких функций?
Это будет более выгодно использовать такие функции, чем обычные примитивы синхронизации, такие как мьютексы и т. д?
ОС: Windows, Linux, Solaris & VxWorks
5 ответов
до C11
в библиотеке C их нет.
в Linux gcc предоставляет некоторые -- look for __sync_fetch_and_add
, __sync_fetch_and_sub
и так далее.
в случае Windows, искать InterlockedIncrement
, InterlockedDecrement``,
InterlockedExchange`, и так далее. Если вы используете gcc в Windows, я бы предположил, что он также имеет те же встроенные модули, что и в Linux (хотя я этого не проверял).
на Солярисе, это будет зависеть. Вероятно, если вы используете GCC, возможно (повторюсь) есть те же встроенные модули, что и в Linux. В противном случае есть библиотеки, плавающие вокруг, но ничего действительно стандартизированного.
C11
C11 добавил (разумно) полный набор атомарных операций и атомарных типов. Операции включают такие вещи, как atomic_fetch_add
и atomic_fetch_sum
(и *_explicit
версии же, которые позволяют указать модель заказ вам нужно, где по умолчанию всегда использовать memory_order_seq_cst
). Есть также fence
функции, такие как atomic_thread_fence
и atomic_signal_fence
.
типы соответствуют каждому из обычных целочисленных типов, например, atomic_int8_t
соответствующую int8_t
и atomic_uint_least64_t
corrsponding к uint_least64_t
. Это typedef
имена, определенные в <stdatomic.h>
. Чтобы избежать конфликтов с любыми существующими именами, вы можете опустить заголовок; сам компилятор использует имена в пространстве имен реализатора (например, _Atomic_uint_least32_t
вместо atomic_uint_least32_t
).
"выгодно" - это ситуативно. Производительность всегда зависит от обстоятельств. Вы можете ожидать, что произойдет что-то замечательное, когда вы переключите мьютекс для чего-то подобного, но вы можете не получить никакой выгоды (если это не так популярно в случае) или сделать все хуже (если вы случайно создадите "спин-замок").
на всех поддерживаемых платформах, вы можете использовать атомарные операции Глиба. На платформах, которые имеют встроенные атомарные операции (например, инструкции по сборке), glib будет использовать их. На других платформах он вернется к использованию мьютексов.
Я думаю, что атомарные операции могут дать вам ускорение скорости, даже если мьютексы реализованы с их помощью. С мьютексом у вас будет как минимум два атомарных ops (lock & unlock), плюс фактическая операция. Если атомарный op доступно, это одна операция.
Не уверен, что вы подразумеваете под библиотеки C времени выполнения. Сам язык или стандартная библиотека не предоставляют вам никаких средств для этого. Вам нужно будет использовать конкретную библиотеку/API для ОС. Кроме того, не обманывайтесь sig_atomic_t
-- Они не то, что кажется на первый взгляд и полезны только в контексте обработчиков сигналов.
в Windows есть InterlockedExchange и тому подобное. Для Linux, вы можете взять атомарные макросы glibc - они портативны (см. i486 atomic.h). Я не знаю решения для других операционных систем.
В общем, вы можете использовать xchg
инструкция по x86 для атомарных операций (работает и на двухъядерных процессорах).
Что касается вашего второго вопроса, нет, я не думаю, что использование атомарных операций будет быстрее, чем используя мьютексы. Например, библиотека pthreads уже реализует мьютексы с атомарными операциями, что очень быстро.