2016-06-07 2 views
5

В Java поле не обязательно должно быть изменчивым, если вы обращаетесь к нему только после присоединения к потоку, который его мутировал; соединение принудительно выполняет действие до отношения.Нужен ли мне volatile, если я вызываю Thread.Join()?

Как насчет в C#? С приведенным ниже кодом я уверен, что увижу обновленное значение _value после вызова Join() или мне нужно сделать _value volatile?

private String _value = "FOO" 

public void Foo() 
{ 

    Thread myThread = new Thread(Bar); 
    myThread.Start(); 
    myThread.Join(); 
    Console.WriteLine("[Main Thread] _val = "+ _value); 

} 

public void Bar() 
{ 

    for(int i=0; i<1000; i++) 
    { 
     Console.WriteLine("Looping"); 

     if(i==75) 
     { 
      _value="BAR"; 
     } 
    } 
    Console.WriteLine("DONE Looping"); 
} 

В моем фрагменте кода всегда печатается «BAR»?

+0

Вам не нужна синхронизация для этого кода (кроме '.Join()'). Даже без этого вам не нужно будет использовать 'volatile', так как изменение строковой ссылки является атомной операцией, поэтому нет возможности наблюдать за разрытым значением. –

+0

@MatthewWatson, вы имеете в виду, что из-за Join() основной поток гарантированно будет загружать новое значение _value, заданное другим потоком? – AfterWorkGuinness

+0

Да, другой поток завершится после возвращения '.Join()'. –

ответ

1

Общие действия синхронизации потоков выполняют полный барьер памяти. Начать и присоединяться и заканчивать поток наверняка среди них. Без этого всякие программы будут работать неправильно.

Эти гарантии часто не документируются, но практически очевидны. Увы, я не могу представить убедительных доказательств, кроме как сказать, что все остальное будет сумасшедшим.

См. this list как свидетельство того, что это не задокументировано и что имущество, которое вы ищете, скорее всего, имеет место.

В моем фрагменте кода будет ли печататься «БАР»?

Да. Я считаю, что все эксперты согласятся на это. Вот простой пример кода, который делает ту же точку:

int x = 0; 
Thread myThread = new Thread(() => x = 1); 
myThread.Start(); 
myThread.Join(); 
x = 2; 
Console.WriteLine(x); //Prints 2 because of memory barriers on exit and on Join. 
+0

Он показывает, в каком порядке выводятся строки. Консоль синхронизирована. Поэтому это хороший тест на глобальный порядок. Вместо этого можно использовать глобальный вариант, если вам это нравится больше. @sstan – usr

+0

Предположим, что существует барьер, выпущенный объединением, как можно было распечатать 2,1? (Это не может быть.) – usr

+0

Обратите внимание, что это гарантировано, потому что Console.WriteLine - это запись на «внешний ресурс». –

3

Во-первых: Мое общее правило, если я задаю вопрос «ли это нужно быть энергозависимой?» то я недостаточно понимаю модель памяти, чтобы писать код с низким уровнем блокировки.

Просто поставьте предмет под замок и не пытайтесь использовать код с низким уровнем блокировки без необычно повод и совет эксперта.

Я не такой специалист. Я почти не знаю о модели памяти C# для записи кода с низким уровнем блокировки с уверенностью, что это будет правильно, если работать на аппаратном оборудовании с слабой памятью.

Для решения вашего актуального вопроса:

я гарантированно увидеть обновленное значение _value после вызова Join() или мне нужно сделать _value летучим?

Ответ на ваш вопрос находится в C# спецификации, которые я привожу здесь для вашего удобства:

Исполнение C# программных средств, таких, что побочные эффекты каждого выполняющегося потока сохраняются в критической точки выполнения. Побочный эффект определяется как чтение или запись изменчивого поля, запись в энергонезависимую переменную, запись на внешний ресурс и выброс исключения. Критические точки выполнения, в которых должен сохраняться порядок этих побочных эффектов, - это ссылки на изменчивые поля, операторы блокировки и создание и прекращение потоков.

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

+0

Ничего, поэтому это указано в конце концов. Хотя многие тайны остаются с другими распространенными примитивами (не этот вопрос). Этот список из спецификации - это падение на горячем камне. – usr

Смежные вопросы