Общепризнанно (я верю!), что 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
каждый раз, когда он пульсирует, но я заинтригован, знаю ли он, что необходимо.