Потокобезопасные атомные операции в gcc

В программе, над которой я работаю, у меня много кода:

pthread_mutex_lock( &frame->mutex );
frame->variable = variable;
pthread_mutex_unlock( &frame->mutex );

Это явно пустая трата циклов CPU, если среднюю инструкцию можно просто заменить атомным хранилищем. Я знаю, что gcc вполне способен на это, но я не смог найти много документации по таким простым потокобезопасным атомным операциям. Как заменить этот набор кода на атомную операцию?

(Я знаю, что простые хранилища теоретически должны быть атомарными, но я не хочу надеяться, что оптимизатор не навредит своей атомности в какой-то момент процесса.)

Уточнение: я не нуждаюсь в том, чтобы они были строго атомарными; эти переменные используются исключительно для синхронизации потоков. То есть Thread B считывает значение, проверяет, правильно ли оно, и если оно не правильно, оно спит. Поэтому, даже если Thread A обновляет значение, и Thread B не реализует его обновление, это не проблема, так как это означает, что Thread B спит, когда это действительно не нужно, и когда он просыпается, значение будет быть правильным.

Ответ 1

Вы можете проверить документацию gcc. Для текущей версии gcc (4.3.2) это будет глава 5.47 Встроенные функции для доступа к атомной памяти - для других версий gcc проверьте свои Docs. Он должен быть в главе 5 "Расширения семейства языков C".

Кстати, компилятор C абсолютно не гарантирует, что простые операции хранилища являются атомарными. Вы не можете полагаться на это предположение. Для того чтобы машинный код операции выполнялся атомарно, ему нужен префикс LOCK.

Ответ 2

До определенной точки атомные операции в C были предоставлены прямо из источников ядра через заголовок atomic.h.

Однако наличие заголовков ядра, используемых непосредственно в коде пользовательского пространства, является очень плохой практикой, поэтому заголовочный файл atom.h был удален некоторое время назад. Вместо этого мы теперь используем "GCC Atomic Builtins", которые намного лучше и надежнее.

Существует очень хорошее объяснение, предоставленное Тудором Голубенко в его блоге. Он даже обеспечивает замену исходного файла atomic.h, если у вас есть какой-то код, который ему нужен.

К сожалению, я новичок в stackoverflow, поэтому я могу использовать только одну ссылку в своих комментариях, поэтому проверьте сообщение Tudor и получите просветленный.

Ответ 3

В x86 и большинстве других архитектур выровненные 4-байтовые чтения и записи всегда являются атомарными. Оптимизатор может пропустить/изменить порядок чтения и записи в одном потоке.

Что вы хотите сделать, это сообщить компилятору, что другие потоки, возможно, коснулись этой памяти. (Побочный эффект pthread_mutex_lock говорит компилятору, что другие потоки могли коснуться любой части памяти.) Вы можете увидеть volatile рекомендованный, но это не в спецификации C, а GCC не интерпретирует volatile, что путь.

asm("" : "=m" (variable));
frame->variable = variable;

является механизмом, специфичным для GCC, чтобы сказать, что "variable было записано, перезагрузите его".

Ответ 4

AFAIK, вы не можете префикс команд MOV с помощью LOCK; это разрешено только для операций RMW. Но если он использует простой магазин, ему может также понадобиться барьер памяти, который подразумевается с помощью мьютекса, а также с инструкциями, которые позволяют LOCK.

Ответ 5

Как я могу видеть, вы используете платформу gnu для разработки, поэтому можно с уверенностью сказать, что glic предоставляет тип данных, содержащий атомные возможности, 'sig_atomic_t'. Таким образом, этот подход может обеспечить вам атомные операции на уровнях ядра. а не gcc.