Упрощенный вопрос, чтобы дать более четкое представление о том, что я на самом деле спрашиваю
У меня есть два потока, назовите их A
и B
.Они разделяют один объект типа Foo
, который имеет поле с именем Name
и хранится в массиве типа Foo[]
с индексом 0
.Потоки всегда будут обращаться к индексу 0
в порядке, который уже гарантирован системой, поэтому нет условия гонки для потока B
перед потоком A
.
Порядок такой:
// Thread A
array[0].Name = "Jason";
// Thread B
string theName = array[0].Name
Как я уже говорил, этот порядок уже гарантирован, у нет способа для потока B прочитать значение перед потоком A
Я хочу убедиться в том, что две вещи:
- Оба потока получают последний объект с индексом 0.
- Поток
B
всегда получает последнее значение в.Name field
Маркировка Name
как volatile не является опцией, поскольку реальные объекты намного сложнее и даже имеют собственные структуры, которые даже не могут иметь прикрепленный к ним атрибут volatile.
Теперь, удовлетворяя 1 легко (всегда получая последний объект), вы можете сделать .VolatileRead:
// Thread A
Foo obj = (Foo)Thread.VolatileRead(ref array[0]);
obj.Name = "Jason";
// Thread B
Foo obj = (Foo)Thread.VolatileRead(ref array[0]);
string theName = obj.Name
Или вы можете вставить барьер памяти:
// Thread A
array[0].Name = "Jason";
Thread.MemoryBarrier();
// Thread B
Thread.MemoryBarrier();
string theName = array[0].Name
Итак, мой вопрос: достаточно ли этого для удовлетворения условия 2?Что я всегда получаю последнее значение из полей объекта, который я зачитываю?Если объект с индексом 0
не изменился, а Name
изменился.Сделает ли VolatileRead
или MemoryBarrier
для индекса 0
, что все поля в объекте с индексом 0
также получат свои последние значения?