I got confused on volatile
for reference type .
I understand that for primitive type, volatile
can reflect value changes from another thread immediately. For reference type, it can reflect the address changes immediately. However, what about the content of the object. Are they still cached?
(Assuming List.Add()
is an atomic operation)
For example, I have:
class A
{
volatile List<String> list;
void AddValue()
{
list.Add("a value");
}
}
If one thread calls the function AddValue
, the address of list does not change, will another thread get updated about the "content" change of the list, or the content may be cached for each thread and it doesn't update for other threads?
I understand that for primitive type, volatile can reflect value changes from another thread immediately
You understand incorrectly in at least three ways. You should not attempt to use volatile until you deeply understand everything about weak memory models, acquire and release semantics, and how they affect your program.
First off, be clear that volatile affects variables, not values.
Second, volatile does not affect variables that contain values of value types any differently than it affects variables that contain references.
Third, volatile does not mean that value changes from other threads are visible immediately. Volatile means that variables have acquire and release semantics. Volatile affects the order in which side effects of memory mutations can be observed to happen from a particular thread. The idea that there exists a consistent universal order of mutations and that those mutations in that order can be observed instantaneously from all threads is not a guarantee made by the memory model.
However, what about the content of the object?
What about it? The storage location referred to by a volatile variable of reference type need not have any particular threading characteristics.
If one thread calls the function AddValue, the address of list does not change, will another thread get updated about the "content" change of the list.
Nope. Why would it? That other thread might be on a different processor, and that processor cache might have pre-loaded the page that contains the address of the array that is backing the list. Mutating the list might have changed the storage location that contains the address of the array to refer to some completely different location.
Of course, the list class is not threadsafe in the first place. If you're not locking access to the list then the list can simply crash and die when you try to do this.
You don't need volatile; what you need is to put thread locks around accesses to the list. Since thread locks induce full fences you should not need half fences introduced by volatile.
It's worse than that.
If you concurrently access an object that isn't thread-safe, your program may actually crash. Getting out-of-date information is not the worst potential outcome.
When sharing .NET base class library objects between threads, you really have no choice but to use locking. For lockless programming, you need invasive changes to your data structures at the lowest levels.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With