2011-12-16 2 views
-7

Вот код, который я пытался на своей рабочей станции.Нам действительно нужно ключевое слово VOLATILE в C#?

class Program 
{ 
    public static volatile bool status = true; 

    public static void Main() 
    { 
     Thread FirstStart = new Thread(threadrun); 
     FirstStart.Start(); 

     Thread.Sleep(200); 

     Thread thirdstart = new Thread(threadrun2); 
     thirdstart.Start(); 

     Console.ReadLine(); 

    } 

    static void threadrun() 
    { 
     while (status) 
     { 
      Console.WriteLine("Waiting.."); 
     } 
    } 

    static void threadrun2() 
    { 
     status = false; 
     Console.WriteLine("the bool value is now made FALSE"); 
    } 
} 

Как вы можете видеть, я выстрелил три нити в Main. Затем, используя точки останова, я отслеживал потоки. Моя первоначальная концепция заключалась в том, что все три потока будут запускаться одновременно, но мой поток точки останова показал, что поток выполнения потока последовал один за другим (и так был выходной формат, а именно: от верхнего к нижнему исполнению потоков). Ребята, почему это происходит?

Кроме того, я попытался запустить ту же программу, не используя ключевое слово volatile в объявлении, и не нашел никаких изменений в выполнении программы. Я сомневаюсь, что ключевое слово volatile не имеет практического использования вживую. Я где-то ошибаюсь?

+0

Как вы ожидаете, что это произойдет при использовании отладчика? – JonH

+1

Почему вы считаете, что потоки будут выполняться одновременно? – Alan

+0

Тогда почему бы мне не получить разницу в выходе при использовании и не использовать их? –

ответ

3

Хорошо, я попробую объяснить очень длинную историю как можно короче:

Номер 1: Попытка проверить поведение потоков с отладчиком так же полезно, как раз работаю многопоточную программу и сделать вывод, что он отлично работает, потому что из 100 тестов никто не провалился: НЕПРАВИЛЬНО! Темы ведут себя совершенно недетерминированным (кто-то скажет случайным образом), и вам нужны разные методы, чтобы убедиться, что такая программа будет работать правильно.

Номер 2: Использование volatile станет ясно, как только вы удалите его, а затем запустить программу в режиме отладки, а затем переключиться в режим Release. Я думаю, у вас будет сюрприз ... Что происходит в режиме Release, так это то, что компилятор будет оптимизировать код (это включает в себя инструкции по переупорядочению и кэширование значений). Теперь, если ваши два потока выполняются на разных процессорных ядрах, то ядро, выполняющее поток, проверяющий значение status, будет кэшировать его значение, а не повторно проверять его. Другой поток установит его, но первый никогда не увидит изменения: тупик! volatile предотвращает такую ​​ситуацию.

В некотором смысле volatile является защитой в случае, если код фактически не работает (и, скорее всего, не будет), как вы думаете, будет в многопоточном сценарии.

+0

Это немного вводит в заблуждение несколькими способами. Это не так много режима выпуска, это проблема, но работает без отладчика. Не имеет значения, работает ли он на разных ядрах, многопоточность с разделением времени имеет точно такую ​​же проблему, потому что это не смешная глобальная проблема с упорядочением, а проблема «значение находится в регистре, а не перечитывается из кеша, поэтому он никогда не меняется ». – harold

+1

@harold: Я прошу отличиться в отладчике. Дело не в подключении отладчика, а в компиляции с оптимизацией или без нее. Вы можете воспроизвести эту проблему даже без использования IDE. – Tudor

+0

Ну, это было бы верно для C, но компилятор C# в любом случае не оптимизирован, несмотря на то, что может сказать флаг оптимизации. Это все ошибки компилятора JIT. – harold

2

Тот факт, что ваш простой код не ведет себя диверсивно с изменчивым, ничего не значит. Ваш код слишком прост и не имеет ничего общего с изменчивым. Вам нужно написать очень интенсивный вычислительный код для создания четко видимого состояния гонки памяти.

Кроме того, ключевое слово volatile может быть полезным на других платформах, кроме x86/x64, с другими моделями памяти. (Я имею в виду, например, Itanium.)

Joe Duffy написал интересную информацию о volatile в своем блоге. Я настоятельно рекомендую его прочитать.

+0

Спасибо вам всем, ребята ... Я пришел к выводу, что выполнение потока полностью НЕДЕТЕРМИНИСТИЧЕСКОЕ и зависит исключительно от типа процессора, скорости и техники оптимизации кода. И Volatile Usability можно отметить на крупномасштабной вычислительной машине, а не в небольшом отладчике. Еще раз спасибо. Счастливое кодирование. –

4

Ваш метод мышления является ошибочным.

Сам характер проблем, связанных с потоками, заключается в том, что они не детерминированы. Это означает, что то, что вы наблюдали, потенциально не является индикатором того, что может произойти в будущем.

Это самая природа того, почему многопоточное программирование является «трудным». Он часто бросает вызов специальному тестированию или даже самому модульному тестированию. Единственный способ сделать это эффективно - это понять весь ваш стек программного обеспечения и оборудования, а также показать все возможные случаи использования государственных машин.

Таким образом, программирование с резьбой - это не то, что вы видели, это то, что может случиться, как бы невероятно.

0

Затем с использованием контрольных точек я отслеживал потоки. Моя первоначальная концепция состояла в том, что все три потока будут запускаться одновременно, но мой поток прерываний показал, что поток выполнения потока последовал за одним после другого (а также был выходным форматом, т.е. сверху вниз, потоков). Ребята, почему это происходит?

Отладчик временно приостанавливает потоки, чтобы облегчить отладку.

Я сомневаюсь, что ключевое слово volatile не имеет практического использования в реальном времени. Я иду где-то неправильно?

The Console.WriteLine звонки очень вероятно фиксируя маскировать проблему. Они, скорее всего, создают для вас необходимый барьер памяти для вас неявно. Вот действительно простой фрагмент кода, который демонстрирует, что на самом деле существует проблема, когда volatile не используется для объявления переменной stop.

Скомпилируйте следующий код с конфигурацией Release и запустите его вне отладчика.

class Program 
{ 
    static bool stop = false; 

    public static void Main(string[] args) 
    { 
     var t = new Thread(() => 
     { 
      Console.WriteLine("thread begin"); 
      bool toggle = false; 
      while (!stop) 
      { 
       toggle = !toggle; 
      } 
      Console.WriteLine("thread end"); 
     }); 
     t.Start(); 
     Thread.Sleep(1000); 
     stop = true; 
     Console.WriteLine("stop = true"); 
     Console.WriteLine("waiting..."); 
     t.Join(); 
    } 
} 
Смежные вопросы