Я хотел бы написать небольшую программу, которая наглядно иллюстрирует поведение volatile
ключевого слова. В идеале это должна быть программа, которая выполняет одновременный доступ к энергонезависимому статическому полю и из-за этого ведет себя некорректно.
Добавление ключевого слова volatile в ту же программу должно решить проблему.
Этого мне не удалось достичь. Даже несколько раз попробовав, включив оптимизацию и т. Д., Я всегда получаю правильное поведение без ключевого слова volatile.
У вас есть идеи по этой теме? Вы знаете, как смоделировать такую проблему в простом демонстрационном приложении? Это зависит от железа?
Да, это зависит от оборудования (вы вряд ли увидите проблему без нескольких процессоров), но это также зависит от реализации. Спецификации модели памяти в спецификации CLR допускают то, что реализация CLR Microsoft не всегда делает.
источник
На самом деле это не вопрос неисправности, когда ключевое слово volatile не указано, более того, когда оно не указано, может произойти ошибка. Обычно вы знаете, когда это так, лучше, чем компилятор!
Самый простой способ подумать об этом - это то, что компилятор мог бы, если бы захотел, встроить определенные значения. Помечая значение как изменчивое, вы говорите себе и компилятору, что значение может действительно измениться (даже если компилятор так не считает). Это означает, что компилятор не должен вставлять значения в строку, сохранять кеш или считывать значение раньше (в попытке оптимизировать).
На самом деле это не то же самое ключевое слово, что и в C ++.
MSDN имеет краткое описание здесь . Вот, возможно, более подробный пост по темам волатильности, атомарности и взаимоблокировки.
источник
Это сложно продемонстрировать на C #, поскольку код абстрагируется виртуальной машиной, поэтому в одной реализации этой машины он работает правильно без изменчивости, в то время как в другой может произойти сбой.
Однако в Википедии есть хороший пример того, как продемонстрировать это на языке C.
То же самое может произойти в C #, если JIT-компилятор решит, что значение переменной не может измениться в любом случае, и, таким образом, создает машинный код, который даже больше не проверяет его. Если теперь другой поток изменяет значение, ваш первый поток все еще может попасть в цикл.
Другой пример - ожидание занятости.
Опять же, это может произойти и с C #, но это сильно зависит от виртуальной машины и от JIT-компилятора (или интерпретатора, если у него нет JIT ... теоретически, я думаю, что MS всегда использует JIT-компилятор, а также Mono использует один; но вы можете отключить его вручную).
источник
Вот мой вклад в коллективное понимание этого поведения ... Это немного, просто демонстрация (на основе демонстрации xkip), которая показывает поведение изменчивого стиха с энергонезависимым (то есть "нормальным") значением int, бок о бок -в той же программе ... это то, что я искал, когда нашел эту ветку.
using System; using System.Threading; namespace VolatileTest { class VolatileTest { private volatile int _volatileInt; public void Run() { new Thread(delegate() { Thread.Sleep(500); _volatileInt = 1; }).Start(); while ( _volatileInt != 1 ) ; // Do nothing Console.WriteLine("_volatileInt="+_volatileInt); } } class NormalTest { private int _normalInt; public void Run() { new Thread(delegate() { Thread.Sleep(500); _normalInt = 1; }).Start(); // NOTE: Program hangs here in Release mode only (not Debug mode). // See: http://stackoverflow.com/questions/133270/illustrating-usage-of-the-volatile-keyword-in-c-sharp // for an explanation of why. The short answer is because the // compiler optimisation caches _normalInt on a register, so // it never re-reads the value of the _normalInt variable, so // it never sees the modified value. Ergo: while ( true )!!!! while ( _normalInt != 1 ) ; // Do nothing Console.WriteLine("_normalInt="+_normalInt); } } class Program { static void Main() { #if DEBUG Console.WriteLine("You must run this program in Release mode to reproduce the problem!"); #endif new VolatileTest().Run(); Console.WriteLine("This program will now hang!"); new NormalTest().Run(); } } }
Выше есть несколько действительно отличных кратких объяснений, а также несколько отличных ссылок. Спасибо всем за то, что помогли мне
volatile
сориентироваться (по крайней мере, достаточно, чтобы не полагаться на то,volatile
где был мой первый инстинктlock
).Ура и спасибо за ВСЮ рыбу. Кит.
PS: Я бы очень заинтересован в демо исходном запросе, который был: «Я хотел бы видеть в статический летучий Int ведет себя правильно , где это статический Int ведет себя плохо.
Я пробовал и не смог решить эту задачу. (На самом деле я довольно быстро сдался ;-). Во всем, что я пробовал со статическими варами, они ведут себя «правильно» независимо от того, изменчивы они или нет ... и мне бы хотелось получить объяснение, ПОЧЕМУ это так, если это действительно так ... компилятор не кэширует значения статических переменных в регистрах (т.е. вместо этого кэширует ссылку на этот адрес кучи)?
Нет, это не новый вопрос ... это попытка вернуть сообщество к исходному вопросу.
источник
Я наткнулся на следующий текст Джо Альбахари, который мне очень помог.
Я взял пример из приведенного выше текста, который немного изменил, создав статическое изменчивое поле. Когда вы удалите
volatile
ключевое слово, программа заблокируется на неопределенный срок. Запустите этот пример в режиме выпуска .class Program { public static volatile bool complete = false; private static void Main() { var t = new Thread(() => { bool toggle = false; while (!complete) toggle = !toggle; }); t.Start(); Thread.Sleep(1000); //let the other thread spin up complete = true; t.Join(); // Blocks indefinitely when you remove volatile } }
источник