On Thu, 2007-10-25 at 21:50 -0700, Ian Lance Taylor wrote: > David Miller <[EMAIL PROTECTED]> writes: > > > From: Ian Lance Taylor <[EMAIL PROTECTED]>
I'm having some trouble following this discussion. In serial code, assume we permit a register to transiently alias a variable. For this to be viable, the compiler must know all the references to the variable, to ensure the register is used instead, or, store back the value in the variable. Four things seem to govern this: rules on sequence points, rules on permitted aliasing, volatile, and facts deduced by the compiler from analysing the context. As I understand it volatile is typically used as a 'hint' to the compiler that there could be aliases it cannot see. This is independent of the use suggesting asynchronous changes in a hardware port for example, although the effect is the same. OK, now in POSIX with threading, we can use mutex locks to serialise access to some variables. We have to assume that if I lock, write, and unlock, and another thread does lock, read, unlock, that the read/write operations are ordered: the start of one operation must come after the completion of the other (although which happens first isn't determined without further investigation of the actual code). So the rule must be that any write protected by a mutex like this must be put somewhere that a protected read will fetch that write, IF the read happens afterwards, whether or not the variable is volatile. I have to deduce from this that unlocking a mutex must dump any values in registers aliasing store into that store, as well as ensuring the cache organises to ensure a read from the other thread after it locks the mutex, will fetch that value -- "as if" the write went through to memory and the read was from memory (even if the actual value never gets into memory). So: accesses to any variable read or written whilst protected by a lock are ordered with respect to any other accesses protected by a lock in any other thread, whether or not the variable is aliased or volatile. I'm deducing this from existing practice NOT any standards: in this circumstance, volatile is NOT needed. That leaves open several questions. One is: what can we say about a write in thread A *prior* to a lock being set and released, and a read in thread B *after* a lock is set and released, where the read is certain to be following the write temporaly, for a variable NOT accessed during the exclusion period by either thread? I believe this also must be guaranteed, volatile or not, standards or not, by considering the trivial example of storing a pointer in thread A, then reading it in thread B, where the variable is mutexed. We have to assume the store the pointer POINTS AT is also subject to the ordering constraint that applied to the pointer, or most of the utility of mutexed synchronisation is lost. For example when mutexing a queue where threads enqueue and dequeue data to ensure you properly retrieve the pointer in the queue is useless if the data pointed at isn't guaranteed. SO I would have to conclude something like: if a mutex synchronises variables ROOT, then all variables REACHABLE from ROOT must also be synchronised. And in effect that means ALL variables must be synchronised, unless the compiler is exceedingly smart! AFAICS this means that the compiler must recognize mutex.unlock and dump registers into the variables they alias at this point. The OS/library function then takes care of cache synchronisation etc. I'm not sure I understand so I'd welcome any feedback on this: I don't see any role at all for volatile here. What I mean is that we CANNOT require volatile on all that data, it would be a pain and equivalent to making everything volatile, defeating optimisations. Rather, the 'volatility' is temporal and transient and associated with a mutex operation. [BTW I think this sucks, the need to synchronise ALL memory on mutexing is far too heavy] -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net