Общепризнанно (я верю!), что lock будет принудительно перезагружать любые значения из полей (по существу действуя как барьер или ограждение памяти), моя терминология в этой области немного ослабляется, я боюсь), вследствие чего поля, которые только когда-либо доступны внутри lock, сами по себе не должны быть volatile.
(Если я уже не прав, просто скажите!)
Хороший комментарий был здесь поднят, спрашивая, верно ли то же самое, если код выполняет Wait() - то есть, когда он был Pulse() d, будет ли он перезагружать поля из памяти или они могут находиться в регистре (и т.д.).
Или проще: нужно ли поле volatile, чтобы убедиться, что текущее значение получено при возобновлении после Wait()?
Посмотрев на отражатель, Wait называет ObjWait, который равен managed internalcall (так же, как Enter).
Сценарий, о котором идет речь, был:
bool closing;
public bool TryDequeue(out T value) {
lock (queue) { // arbitrary lock-object (a private readonly ref-type)
while (queue.Count == 0) {
if (closing) { // <==== (2) access field here
value = default(T);
return false;
}
Monitor.Wait(queue); // <==== (1) waits here
}
...blah do something with the head of the queue
}
}
Очевидно, я мог бы просто сделать это volatile, или я мог бы переместить это так, чтобы я выходил и повторно вводил Monitor каждый раз, когда он пульсирует, но я заинтригован, знаю ли он, что необходимо.