Функции для выполнения атомарных операций

существуют ли функции для выполнения атомарных операций (например, инкремент / декремент целого числа) и т. д., поддерживаемые библиотекой времени выполнения 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 уже реализует мьютексы с атомарными операциями, что очень быстро.