[concurrency-interest] Waiting for object value to be available.

David Holmes dholmes at dltech.com.au
Tue Aug 23 19:54:02 EDT 2005


Being in a different time-zone gives me the advantage of seeing the story
unwind so that all the requirements are extracted.

>From what I read Peter wants a "waitable reference" as has been discussed,
which is very much like a settable FutureTask. *However* the part that I
don't think people have picked up on yet is the use of the ReadWriteLock. If
I understand Peter correctly, the intent is that the value of the object
can't be changed while anybody is using that value - which in this case
means a thread is running that task. So the intent then is that the getter
will do something like:

    readLock.acquire();
    try {
       V val = value.get();
       process(val);
    }
    finally {
      readLock.release();
    }

However the code that Peter originally showed does not do this. It simply
held the readLock while doing the get() and returning the value. Hence as
soon as the value was returned and the readLock released then the value
could be changed and two (or more) different versions of the task could be
being processed.

So the interface that I see for this is more like:

    E acquireValue();
    void releaseValue(E val);
    void setValue(E val);

and so the client of this would do:

    E val = value.acquireValue();
    try {
        process(val);
    }
    finally {
       value.releaseValue(val);
    }

The intent being that if the number of successful acquires exceed the number
of successful releases then the current value is being used and so setValue
will block.

Does this represent what you want to do Peter? If so we can pursue
implementation approaches.


A couple of additional notes. In the original code you have:

  public E read()throws InterruptedException{
    _lock.readLock().lockInterruptibly();
     try{
       while(_item==null)
            _itemAvailable.wait();

You can't do this. The Condition is associated with the WriteLock and to
wait on it you must hold the WriteLock. To fix this per acquireValue above
you would do:

    writeLock.lockInterruptibly();
    try {
       while(item == null)
             itemAvailable.await();  // NOTE await NOT Object.wait
       readLock.lock(); //  writer can acquire readLock to downgrade
       return item;
    }
    finally {
       writeLock.unlock();
    }

and in releaseValue() you would do the readLock.unlock(). Of course you need
to take great care in the client code to ensure the releaseValue() is always
called even if the client throws an exception etc.


Second issue: volatile. You only need to use volatile if you will access a
shared mutable variable without using any other form of synchronization.
Other forms of synchronization include always accessing the variable with
the same lock held (or for ReadWrite locks a read-lock or write-lock from
the same ReadWriteLock); or correctly using atomic variables or other
volatile variables that protect/coordinate access to the variable concerned.
In your code you always access _item with a lock held, so it need not be
volatile. The use of Locks provides all the necessary memory model
guarantees that ensures that all updates are visible where they need to be.

Tim's point was that you could use the volatility of item to do a safe
fast-path through the code, for the case where item is not null, to avoid
the need for acquiring a lock ie it would be a performance boost. That
comment doesn't account for the "nobody can set while the value is being
used" semantics that I think you want, however.

I hope this helps.

Cheers,
David Holmes

PS. Please try and use a mail program that correctly indents or prefixes
text written by others - it is vary hard to see in your mails what comments
are from you and what are quoted from other posters. Thanks.



More information about the Concurrency-interest mailing list