Анализирую сабжем одну программку и получаю сабж. Суть такова (от кода оставлена только концепция, мог слегка лажануть — но реальный код по всем признакам рабочий).
Есть некий глобальный объект.
volatile object globalOne = ...
Иногда он модифицируется вот таким вот одноразовым методом одноразового инстанса (т.е. инстанс создается на 1 модификацию и метод вызывается единожды):
class ObjectMutator
{
volatile object oldOne;
volatile object newOne;
volatile bool completed = false;
void Mutate()
{
oldOne = globalOne;
globalOne = this;
newOne = f(...);
completed = true; //3
globalOne = newOne; //1
}
}
И читается он тоже иногда — вот так вот:
var current = globalOne; //2
if(globalOne is ObjectMutator)
{
var mutator = (ObjectMutator)globalOne;
return mutator.completed ? mutator.newOne : mutator.oldOne;
}
else
return current;
CHESS видит store buffer vulnerability и указывает на строки 1 и 2, при этом перестает ругаться, если 1 заменить на
Interloked.CompareExchange(ref globalOne, newOne, this);
Возникает вопрос, в чем заключается этот самый store buffer vulnerability и почему он исчезает при использовании cas.
Поковырявшись в гугле я родил предположение, что теоретически мутатор может совсем не опубликовать свою мутацию — отложить всю свою запись до следующей среды — и будет прав. А Interlocked-операции заставляют его-таки что-нибудь опубликовать.
Фишка в том, что обычно задержку публикации приводят как раз как пример использования volatile (который тут и так есть), а не cas. И кому в итоге верить? В принципе, я больше верю CHESS. Таки согласно ecma, volatile имеет отношение только к упорядочиванию (типа "если наш volatile read увидел эффект вашего volatite write, то...").