How is it a disadvantage? That is _exactly_ why I use it, because it can _not_ be optimized.Gian-Carlo Pascutto wrote:Volatile will basically inhibit optimization on all operations involving the variable. The barrier can put be there only when it's needed. This is a disadvantage of volatile, not an advantage.bob wrote: Without volatile, you end up inserting barriers at inconvenient locations and break other optimizations, where all I want to guarantee is that when I test the value, I test the most current value, not one saved in a register for what could be several minutes.
I lock where appropriate. But there are cases where locking is not needed. This is not something that happens in an O/S, which is why Linux uses the barrier() approach. But in chess, I am willing to eliminate the overhead of unnecessary barriers, and accept the risk that I might just miss the flag getting set and having to wait until another node is searched before I see the change.You can just as well make the opposite argument and say that using volatile will hide the fact that it's parallel from the code and make it more likely that you forget to lock something, whereas the barrier forces you to think it over on every access.But I don't want barrier() calls scattered all over my code to make it harder to read and more likely that I will forget to use one (the often-quoted "sin of omission" in parallel programming).
In Deep Sjeng I just lock, and for those few variables who need to be checked every node so locking them is too expensive (is_aborted), I use accessor functions.
An operating system really doesn't have many cases where that might apply. Perhaps waiting for a buffer when all buffers are allocated, but it is pretty infrequent.
One could make the argument that the best way to share stuff is not via threads, but via the system V shared memory facility, where you put all shared data into a shared block of memory and use a pointer (I used to use shared->variable when I was using processes rather than threads) to make this obvious.
But volatile is cleaner, if you know what you are doing. Because it gives you the opportunity to avoid excessive overhead (barriers/fences thrown in the code in places where it is really not necessary) if you are careful to lock where needed.
I used to have alpha-specific lock/unlock functions in Crafty, where we had to include a barrier else the lock was not safe. So the issues are always there. But I do not ever depend on write order or read order or read/write order being done a certain way for my program to execute correctly. Which is what some of the earlier lockless approaches depended on. Volatile won't cure all evils. Neither will generic barriers. So it is a matter of taste. I personally like the volatile approach although I don't have very many such variables in Crafty since they are not needed. Looks like there are 8 or 9 total, although about half are in a structure that is replicated many times (split blocks).