GCC предлагает хороший набор встроенных функций для атомарных операций.А на MacOS или iOS даже Apple предлагает хороший набор атомарных функций .Однако все эти функции выполняют операцию, например сложение / вычитание, логическую операцию (И / ИЛИ / XOR) или сравнение-и-установку / сравнение-и-обмен.То, что я ищу, - это способ атомарного присвоения / чтения значения 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» к ней, чтобы не изменять ее значение) и для записииспользуйте __sync_val_compare_and_swap
для его записи (так как я знаю его старое значение, поэтому, передавая его, вы всегда будете обмениваться значением), но не приведет ли это к дополнительным накладным расходам?