2014-02-21 8 views
0

Если я создаю переменную в одном потоке, то блокируйте с помощью метода WaitOne(), пока другой поток не присваивает значение той же переменной и не сигнализирует EventWaitHandel. Когда я приступаю к чтению переменной в первом потоке, я гарантированно всегда получаю значение, просто назначенное другим потоком?Перечисляются ли переменные из одного потока «поточно-безопасные» при чтении из другого потока, если используется EventWaitHandel?

(боюсь, я не смог получить значение из кэша процессора из-за некоторой оптимизации, поскольку, насколько я знаю, я не использовал никаких барьеров памяти).

например.

var str = "multi-threading is hard!"; 
var mre = new ManualResetEvent(false); 
Task.Factory.StartNew(() => 
    { 
     str = Console.ReadLine(); 
     mre.Set(); 
    )); 
mre.WaitOne(); 
Console.WriteLine(str); 
+0

Вы сказали, что вы будете использовать 'WaitOne() '. Где? Я бы ожидал этого до Console.WriteLine. – Georg

+0

yup, спасибо за это – markmnl

ответ

1

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

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

WaitOne() вводит неявный барьер памяти, предоставляя вам семантику получения-освобождения, в которой вы нуждаетесь.

Брайан Гедеон и Hans Passant собрать хороший список из нескольких классов в рамках .NET, которые знакомят неявные барьеры памяти: Memory barrier generators

Дополнительная информация: Acquire and release semantics/Acquire and release fences

+0

Я не вижу актуальности переупорядочения здесь, но что барьер памяти неявно очищает его! – markmnl

+0

ahh, спасибо, кстати, как вы знаете, инструкции не могут быть переупорядочены - это из-за барьера памяти? – markmnl

+0

@markmnl Я отредактировал свой первый абзац, объясняя, почему релевантный порядок. – dcastro

0

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

EDIT: Действительно, поле нестабильное.

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

+0

yup Я знаю, что он захвачен, но если переписать проблему с моим собственным классом, проблема все равно будет - я могу отметить ее «volatile» в любом случае. В любом случае, кажется, что барьер памяти является неявным, поэтому нет необходимости. – markmnl