В нашем продукте есть встроенная мьютексная реализация, использующая различные специфичные для платформы и компилятора методы для аппаратных частей. Одно из наших «правил» для некоторого чрезмерно оптимизированного кода, который пытается «обмануть», заключается в том, что если к переменной обращаются за пределами мьютекса и внутри, то эта переменная должна быть объявлена как volatile. Я полагал, что это применимо и к непрозрачным реализациям мьютекса (таким как pthread_mutex_lock / unlock), и это привело к интересной дискуссии.
Один человек утверждал, что это является признаком ошибки компилятора (особенно, когда реализация мьютекса встроена и "непрозрачна" для компилятора). Я привел следующий пример, чтобы оспорить это
int v = pSharedMem->myVariable ;
__asm__ __volatile__(( "isync" : : :"memory" ))
v = pSharedMem->myVariable ;
В этом фрагменте gcc-кода LinuxPPC компилятор не знает об эффектах времени выполнения isync, кроме того, что мы можем сказать через ограничение памяти. Вы найдете такую инструкцию isync в хвостовой части захвата мьютекса, чтобы предотвратить любое выполнение инструкций, которые следуют за успешным захватом мьютекса до фактического удержания мьютекса (поэтому, если загрузка была выполнена до isync, она бы должны быть отброшены).
В этом фрагменте кода у нас есть барьер компилятора, который предотвращает перезапись кода, как если бы он был следующим
int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;
__asm__ __volatile__(( "isync" : : :"memory" ))
или
__asm__ __volatile__(( "isync" : : :"memory" ))
int v = pSharedMem->myVariable ;
v = pSharedMem->myVariable ;
(то есть: оба этих переупорядочения компилятора должны быть запрещены атрибутом volatile )
У нас также есть сам isync, который предотвращает первое переупорядочение во время выполнения (но я не думаю, что предотвращает второе, что не так интересно).
Тем не менее, мой вопрос заключается в том, что если myVariable не объявлен как volatile, является ли ограничение «памяти» достаточным, чтобы gcc обязательно перезагружал «v» после isync? Я все еще был бы склонен к обязательному использованию volatile для такого шаблона, так как этот вид кода слишком чувствителен ко всем встроенным компиляторам платформы. Тем не менее, если мы сократим обсуждение только до GCC и этого фрагмента кода, достаточно ли этого ограничения памяти asm для того, чтобы код генерировался с парой загрузок вместо одной?