condition_variable::notify_all and notify_one don't require lock to be locked

condition_variable::notify_all and notify_one don't require lock to be locked

Post by itaj sherm » Mon, 10 Jan 2011 14:52:19


On Jan 8, 3:17 am, itaj sherman < XXXX@XXXXX.COM > wrote:

Maybe I should refrase my question more precisely:

Suppose there was another member function
condition_variable::locked_notify_all with the same behaviour, but the
following requirement:
caller has to make sure than that condition_variable object is not
being currently used by any other thread. except for if wait*() member
function has been called on other threads and hasn't returned yet,
then each doesn't currently own its argument lock object, and if it
tries to call lock.lock(), such call will block at least until after
the subject call to locked_notify_all returns.

To fulfil that requirement the caller can make sure that the current
thread (that is calling locked_notify_all) owns all such lock objects
(holds them locked) that could be given to wait*() invocations on
other threads, and therefor also keeps them locked at least until
after locked_notify_all returns.

The question is: if such a method had been defined, couldn't
implementations implement it with better performance than the regular
notify_all? specifically, in case that there are no threads currenly
blocked on the condition_variable, it should be possible for
locked_notify_all to verify that and return without any atomic or
blocking operations, because it can access the internals of the
condition_variable object exclusively. On the other had notify_all in
any case must perform at least one atomic read to verify that there
are no blocked threads.

same goes for locked_notify_one.

The example in which I ran into this question is the producer consumer
on a limited queue:

The calls to locked_notify_once below should not perform any atomic/
block operation when no threads are blocked on the condition_variable.

void iQueue::push( cElement const& );
cElement iQueue::pop() const;
bool iQueue::empty() const;
bool iQueue::full() const;

void gConsumer( iQueue& roQueue, std::mutex& roMutex,
std::condition_variable& roCondVarEmpty, std::condition_variable&
roCondVarFull )
{
std::lock_guard aLockGuard( roMutex );
while( true ) {
while( roQueue.empty() ) {
roCondVarEmpty.wait( roMutex );
}
cElement const b( roQueue.pop_front() );
roCondVarFull.locked_notify_once();
roMutex.unlock();
gConsume( b );
roMutex.lock();
}
}


void gProducer( iQueue& roQueue, std::mutex& roMutex,
std::condition_variable& roCondVarEmpty, std::condition_variable&
roCondVarFull )
{
std::lock_guard aLockGuard( roMutex );
while( true ) {
roMutex.unlock();
cElement a( gProduce() );
roMutex.lock();
while( roQueue.full() ) {
roCondVarFull.wait();
}
roQueue.push( b );
roCondVarEmpty.locked_notify_once();
}
}

itaj


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
 
 

condition_variable::notify_all and notify_one don't require lock to be locked

Post by itaj sherm » Mon, 10 Jan 2011 14:56:09


oh, right.
I was confusing with the lib I'm used to in which the conditionVar is
given the mutex on construction, and keeps attached to the same one
through its life.
But, this doesn't change the meaning of my question at all. Maybe just
the wording "the lock" to "a lock" or "some lock".
That only means that notify_all must do some locking on the
conditionVar some way, and in any case (even if no threads are
blocked) it will have to perform some atomic operations. What I'm
saying is that I think there should be a version locked_notify_all
that requires the caller to make sure the conditionVar is mutexed (not
being currently used on another thread, except for inside wait*() on
the waiting i.e. with the lock released).


itaj


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
 
 

condition_variable::notify_all and notify_one don't require lock to be locked

Post by Michae » Wed, 12 Jan 2011 01:37:19


You seem to be making assumptions about the implementation of
condition_variable that aren't warranted. There may be (likely are)
other reasons for internal locking beyond just maintaining the waiter
count.

Anyway, the reason for the mutex is not to ensure that the CV itself
works correctly/robustly, it's to ensure that notifications are not
lost -- the atomic "unlock and block" behavior of wait() being the key
feature here that would be otherwise missing. Without that, it's
impossible to ensure that a notification was not missed. I.e. the
mutex does not guard the CV -- it guards the predicate the CV is
signalling.


Mike


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

condition_variable::notify_all and notify_one don't require lock to be locked

Post by Michae » Thu, 13 Jan 2011 02:01:39


*sigh*


I can't find a coherent question in *any* of your posts. Perhaps you
would have better luck if you didn't embed your supposed question in 8
paragraphs of rambling prose.


Are you prepared to say that all implementations *do* use atomic
operations to detect no waiters? If not, what is your question?


http://www.yqcomputer.com/ +source+code&l=1


It's not obvious to me that you've thought clearly about any of this.


You haven't considered the effects of timed wait (i.e.
condition_variable::wait_for()).


Mike


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]