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

Reply via email to