GCC предлагает прекрасный набор встроенных функций для атомарных операций. А на MacOS или iOS даже Apple предлагает хороший набор элементарных функций . Однако все эти функции выполняют операцию, например сложение / вычитание, логическая операция (И / ИЛИ / ИСКЛЮЧАЮЩЕЕ ИЛИ) или сравнение и установка / сравнение и замена. Я ищу способ атомарного присвоения / чтения значения int
, например:
int a;
/* ... */
a = someVariable;
Вот и все. a
будет прочитан другим потоком, и важно только, чтобы a
имел старое или новое значение. К сожалению, стандарт C не гарантирует, что присвоение или чтение значения является атомарной операцией. Я помню, что однажды я где-то читал, что запись или чтение значения переменной типа int
гарантированно будет атомарным в GCC (независимо от размера int), но я искал везде на домашней странице GCC, и я больше не могу найти этот оператор (возможно, он был удален).
Я не могу использовать sig_atomic_t
, потому что sig_atomic_t не имеет гарантированного размера, а также может иметь другой размер, чем int
.
Поскольку только один поток когда-либо «запишет» значение в a
, в то время как оба потока будут «читать» текущее значение a
, мне не нужно выполнять операции сами по себе атомарно, например:
/* thread 1 */
someVariable = atomicRead(a);
/* Do something with someVariable, non-atomic, when done */
atomicWrite(a, someVariable);
/* thread 2 */
someVariable = atomicRead(a);
/* Do something with someVariable, but never write to a */
Если оба потока собирались писать в a
, тогда все операции должны были бы быть атомарными, но в этом случае это может только тратить время процессора; и у нас очень мало ресурсов ЦП в нашем проекте. Пока мы используем мьютекс для операций чтения / записи a
, и хотя мьютекс удерживается в течение такого крошечного времени, это уже вызывает проблемы (один из потоков является потоком реального времени и блокирует мьютекс заставляет его не выполнять свои ограничения реального времени, что довольно плохо).
Конечно, я мог бы использовать __ sync_fetch_and_add
для чтения переменной (и просто добавить к ней «0», чтобы не изменять ее value), а для записи используйте __ sync_val_compare_and_swap
для записи (так как я знаю его старое значение, поэтому его передача гарантирует, что значение всегда будет меняться), но не добавит ли это ненужных накладных расходов?