Потокобезопасные атомарные операции в gcc - PullRequest
17 голосов
/ 03 октября 2008

В программе, над которой я работаю, у меня много кода следующим образом:

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

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

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

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

Ответы [ 5 ]

16 голосов
/ 03 октября 2008

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

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

15 голосов
/ 04 февраля 2010

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

Однако использование заголовков ядра непосредственно в коде пользовательского пространства - очень плохая практика, поэтому заголовочный файл atomic.h был удален некоторое время назад. Вместо этого мы теперь можем использовать «атомные встраивания GCC», которые являются намного лучшим и более надежным подходом.

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

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

4 голосов
/ 05 октября 2008

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

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

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

- это специальный механизм GCC, который сообщает, что «variable записано, перезагрузите его».

1 голос
/ 03 октября 2008

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

0 голосов
/ 04 февраля 2010

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

...