[dmd-concurrency] draft 7

Andrei Alexandrescu andrei at erdani.com
Mon Feb 1 22:24:11 PST 2010


Fawzi Mohamed wrote:
>> I suggest we resume and start with describing what was unclear, then 
>> specifying the steps we need to take to clarify things better in the 
>> draft. Thanks!
> 
> p 26-27
> "All operations on _balance are now protected by acquiring _guard. It 
> may seem
> there is no need to protect balance with _guard because a double can be 
> read atomi-
> cally, but protection must be there for subtle reasons that shall come 
> forth later. In brief,
> due to today’s aggressive optimizing compilers and relaxed memory 
> models, all access
> to shared data must entail some handshake between threads; no handshake 
> means a
> thread could call obj.balance repeatedly and always get a cached copy 
> form some pro-
> cessor’s cache that never, ever gets updated, in spite of other threads’ 
> frenetic use of
> deposit and withdraw. ( This is one of the ways in which modern 
> multithreading defies
> intuition and confuses programmers versed in classic multithreading.)"
> 
>  From the previous discussion it should be clear that as written it is 
> wrong.

I'm afraid it's your assessment of the situation that is wrong or at 
least in conflict with the texts that I'm perusing.

There are two entities that must be kept in the know with regard to 
proper synchronization: the compiler and the underlying machine. The 
text chose to conflate the two (at least for the time being) in order to 
simplify the discussion.

> Indeed it is better to have a barrier there (if the update would not be 
> atomic, in general case) but there is no need for it in this specific 
> case, as access is atomic.

I'm not sure. Clearly the compiler must be kept informed that no code 
motion and no enregistering should happen. So no contest there.

The problem is whether a barrier should also be inserted. According to 
the four Posix guarantees in Butenhof's book "Programming with Posix 
Threads" page 89, memory visibility by a thread of whatever another 
thread just did is only ensured if you insert a barrier. (Acquiring and 
releasing a mutex both issue barriers.) Butenhof actually goes to 
lengths to insist on it: "This is not only to protect against multiple 
writes---even when a thread only reads data it must use a mutex to 
ensure that it sees the most recent value of the data written while the 
mutex was locked." Later he does mention only a barrier is really 
needed, but he never says _nothing_ is needed.

At the end of the visibility section he says "If you want to write 
portable Pthreads code, you will always guarantee correct memory 
visibility by using the Pthreads memory visibility rules instead of 
relying on any assumptions regarding the hardware or compiler behavior."

If you or I don't know of any machine that would keep on reading a datum 
from its own cache instead of consulting the main memory, we're making 
an assumption. The right thing to do is to keep the compiler _AND_ the 
machine in the loop by using appropriate fencing.

> It is wrong that a cache of a processor might be never updated, it will 
> be updated at some point, and a barrier (in general) will not force the 
> update to be performed immediately.

According to my reading of Butenhof's text, there is nothing stopping a 
machine from delaying reads indefinitely if you don't insert a barrier.

BTW I am not under the misconception that a barrier is a flush 
operation. In fact Butenhof's book, which I use for reference, warns 
exactly about that in large font on page 93.

If you have references to back up your viewpoint please let me know.

> A problem that can come up is that the variable is promoted to a 
> register in a loop and is not updated from the memory.

Yes.

> To avoid this one can use volatile.

Volatile is not in D anymore, and also at that point in the text the 
entire notion is not introduced and not worth introducing.

> This issue is a priory disconnected 
> with the presence of barriers (well one would hope that a correct 
> compiler disables "upgrading to registers" for variables in a locked 
> section crossing the boundary of it, but a priory it doesn't have to be 
> like that, and especially using just memory barriers, I would not trust 
> current compilers to always do the correct thing without a "volatile".

Agreed. There must be a special construct understood by the compiler to 
(a) prevent reordering and enregistering and (b) insert the appropriate 
barrier instruction. One without the other is useless.


Andrei


More information about the dmd-concurrency mailing list