It is generally accepted (I believe!) that a lock will force any values from fields to be reloaded (essentially acting as a memory-barrier or fence - my terminology in this area gets a bit loose, I'm afraid), with the consequence that fields that are only ever accessed inside a lock do not themselves need to be volatile.
(If I'm wrong already, just say!)
A good comment was raised here, questioning whether the same is true if code does a Wait() - i.e. once it has been Pulse()d, will it reload fields from memory, or could they be in a register (etc).
Or more simply: does the field need to be volatile to ensure that the current value is obtained when resuming after a Wait()?
Looking at reflector, Wait calls down into ObjWait, which is managed internalcall (the same as Enter).
The scenario in question was:
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
}
}
Obviously I could just make it volatile, or I could move this out so that I exit and re-enter the Monitor every time it gets pulsed, but I'm intrigued to know if either is necessary.