Недавно я заглянул в реализацию ядра ядра атомарного чтения и записи, и появилось несколько вопросов.Чтение и запись реализации атомной операции в ядре Linux
Сначала соответствующий код из архитектуры ia64:
typedef struct {
int counter;
} atomic_t;
#define atomic_read(v) (*(volatile int *)&(v)->counter)
#define atomic64_read(v) (*(volatile long *)&(v)->counter)
#define atomic_set(v,i) (((v)->counter) = (i))
#define atomic64_set(v,i) (((v)->counter) = (i))
Для обеих операций чтения и записи, кажется, что прямой подход был принят для чтения или записи переменной. Если в другом месте нет другого трюка, я не понимаю, какие гарантии существуют, что эта операция будет атомарной в домене сборки. Я предполагаю, что очевидный ответ будет заключаться в том, что такая операция преобразуется в один код операции сборки, но даже в этом случае, как это гарантируется при учете различных уровней кэша памяти (или других оптимизаций)?
На прочитанных макросах летучий тип используется в трюке для кастинга. Кто-нибудь знает, как это влияет на атомарность здесь? (Обратите внимание, что он не используется в операции записи)
В современных ядрах 'volatile' здесь используется через макрос, называемый' READ_ONCE() '/' WRITE_ONCE'. Устный перевод в моей голове заключается в том, что компиляторам технически разрешено читать/записывать значение * несколько раз. Например. если код копирует значение чтения в локальную переменную, которая затем используется в разных местах. Поэтому мы должны описать это как нечто большее, чем просто предотвращение кэширования ценности локально. Полное описание: https://lwn.net/Articles/508991/ – sourcejedi