> Evan Ireland wrote:
> I am still a bit unclear on the requirements regarding "same" lock,
> and didn't manage to find the section where it was referenced.
>
> Suppose I code (in a writer):
>
> synchronized (a)
> {
> synchronized (b)
> {
> p.x++;
> }
> }
>
> For a reader to be confident of seeing the correctly synchronized
> value of p.x, must they write:
>
> synchronized (a)
> {
> synchronized (b)
> {
> // do something with p.x
> }
> }
>
> or can they write:
>
> synchronized (a)
> {
> // do something with p.x
> }
>
> or:
>
> synchronized (b)
> {
> // do something with p.x
> }
It is my understanding that reading using either of the locks is
correct. If a write is in progress then the read can't proceed until a
and/or b are unlocked. The unlock happens before the lock by the
reader and so the read is guaranteed to see what was written.
On the writer side the compiler could coalesce the implied barriers of
the two unlocks.
> Basically, I suppose what I am having difficulty with is: assuming
> that 'synchronized' implies a read-barrier at start and a
> write-barrier
> at end, the "same" lock requirement would seem to suggest that only
> a partial barrier is required, i.e. only those fields written while
> the writer's lock is held need to be flushed at lock release time
> (otherwise "any" lock would do for the reader).
The barriers could be partial - which I believe is the intent of
requiring the same lock to be used.
> In that case, surely the read-barrier at lock acquire for a reader
would be
> required to go to main memory at least for all fields accessed
within the
> reader's synchronized block (not necessarily for other fields).
Logically it must read the current true value as it appears in "main
memory", but that value might be in a local cache that is guaranteed
consistent with "main memory".
> Or, reworded:
>
> (1) If 'synchronized' read & write barriers are required to
> be "total",
They are not.
> (2) If 'synchronized' read & write barriers are permitted
> to be "partial", then it appears necessary to define the
> semantics so that the read and write barriers are with respect
> only to the actual fields possibly written by the writer and
> possibly read by the reader (which, in the general case, is probably
> uncomputable for the minimal set, but in particular cases could be
> computable as a subset of all cached values).
> If we are to permit "partial" barriers, and we define
> the "write set" of a writer to be the set of fields possibly
written,
> and the "read set" of a reader to be the set of fields possibly
read,
> then if the writer's write-set and the reader's read set both
> contain "p.x", then it is still unclear why a "same" lock
requirement
> would be necessary.
Using the same lock guarantees visibility. A particular implementation
might provide visibility in more circumstances than are actually
guaranteed - such as by making all barriers "total". That doesn't
change what the specification guarantees - or what a portable program
can rely upon.
> Anyway, I think the question boils down to "when readers and writers
> potentially synchronize on multiple locks, which locks are the ones
> owning the responsibility for the necessary read & write barriers?"
> The "same" lock requirement appears to be ambiguous in this case.
Each lock/unlock has defined semantics with respect to the memory
model. An implementation may provide stronger semantics than is
required. An implementation may determine that it can coalesce, or
otherwise optimise, the implied barriers. A program should not assume
anything not guaranteed by the memory model.
Hope this helps.
David Holmes
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:51 EDT