Steeltoe
Steeltoe copied to clipboard
Review usage of `volatile` with `Interlocked`
Steeltoe uses volatile fields and Interlocked.* methods. And sometimes together, which isn't how it is supposed to be used. See https://stackoverflow.com/questions/1186515/interlocked-and-volatile.
The most-official and most-up-to-date information I could find is at https://github.com/VSadov/runtime/blob/main/docs/design/specs/Memory-model.md, originating from https://github.com/dotnet/runtime/issues/63474. Also good info at: http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/.
My conclusions from that are:
volatilefields are always atomically read/assigned (no tearing).- A
longfield can't be declared asvolatile(it would tear). Volatile.Read/Writeprovides non-tearing.
- A
- Reading/writing a
volatilefield flushes all CPU caches. So reading gives a fresh snapshot.- If a field is not declared as
volatile,Volatile.Readgives you the same freshness (assuming non-cached writes).
- If a field is not declared as
- Accessing a
volatilefield limits the potential for reordering instructions (fences). volatilefields result in a full cache refresh (so that nested object properties are consistent).Interlocked.*methods provide at least the same guarantees asvolatilefields.Interlocked.CompareExchangeenables detection of concurrent changes (conditional update), whereas when usingvolatile, the latest writer always wins (potentially undoing the work from others).- If a field is being changed from multiple sources (with potentially conflicting updates), use a
lockto synchronize. Atomic replacement of the field reference would effectively undo concurrent changes.