Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-08-07 15:08:48


--- In boost_at_y..., "Alexander Terekhov" <terekhov_at_d...> wrote:
>
> > Could you explain again what you mean by "cleanup handler"
semantics
> > and why traditional C++ cleanup semantics won't suffice?
>
> e.g. (just an illustration; not real code):
>
> void foo ( )
> {
> { // do some synchronized stuff
>
> synch_region_guard srg( mtxLock );
>
> //...
> // this_region_cleanup_handler function does:
> // a) restore/fix invariants with respect to shared
> // data under protection of still locked mtxLock;
> // b) enforce early unlock (e.g. srg.synch_exit())
> // due to c);
> // c) do some heavy stuff (e.g. somecnd.broadcast) w/o
> // synchronization in place while doing these final
> // operations;
> srg.attach_cleanup_handler( this_region_cleanup_handler,.... );
>
> while ( !.... ) // cancelable wait
> cndSomeState.wait( mtxLock );
>
> //...
> // cleanup handler should become deactivated NOW
> // w/o doing any cleanup actions
> srg.detach_cleanup_handler();
> // w/o srg.detach_ it would still run
> // on exit from synch. region (srg.destr
> // would invoke cleanup handler function)
> //...
>
> }
>
> // do some more non-synchronized stuff
> //...
>
> { // try do some synchronized stuff
>
> synch_region_guard srg( semLock,TRY );
>
> if ( srg.access_granted () ) {
> //...
> if ( .... ) {
> // keep semaphore locked
> srg.disable_cleanup();
> }
> }
> else {
> //...
> }
>
> }
>
> { // try do some synchronized stuff with synch. timeout
>
> synch_region_guard srg( rwlock,timeout,READ_LOCK );
>
> if ( srg.access_granted() ) {
> //...
> }
> else {
> //...
> }
>
> }
>
> }
>
> synch_region_guard basically does three things:
>
> 1) marks the begin of synch. region -- performs
> try/timed/infinite synch. via specified synch
> object and specified (or default) synch operation
> (with timeout for timed synch);
> 2) keeps track of optional synch region cleanup handler;
> 3) on synch region exit performs required cleanup; note
> that an optional cleanup handler could enforce early
> "unlock" in order to do some heavy stuff (e.g. cnd.broadcast)
> w/o synchronization in place while doing these final
> operations.
>
> the idea is to match posix cancellation cleanup handlers
> with *ONE* C++ object (which would work with all kinds of
> locks, semaphores, events, ... any other synchronization
> mechanisms); consider the following C example:
>
> void waiting_writer_cleanup(void *arg)
> {
> rwlock *l;
> int do_broadcast;
> l = (rwlock *) arg;
> do_broadcast = ((--l->waiting_writers == 0) && (l->lock_count >=
0));
> pthread_mutex_unlock(&l->lock);
> /*
> * This only happens if we have been canceled.
> */
> if (do_broadcast)
> pthread_cond_broadcast(&l->wcond);
> }
>
> void lock_for_write(rwlock *l)
> {
> pthread_mutex_lock(&l->lock);
> l->waiting_writers++;
> pthread_cleanup_push(waiting_writer_cleanup, l);
> while (l->lock_count != 0)
> pthread_cond_wait(&l->wcond, &l->lock);
> l->lock_count = -1;
> /*
> * Note the pthread_cleanup_pop executes
> * waiting_writer_cleanup.
> */
> pthread_cleanup_pop(1);
> }
>
> regards,
> alexander.

OK, that's what I thought you meant. Read my question again,
though. I said "and why traditional C++ cleanup semantics won't
suffice?" The need for cleanup handlers of this sort are handled in
C++ through destructors and the RAII idiom and/or catch blocks.
Unlike in C, where POSIX style cleanup stacks are needed because the
language doesn't handle this, there's no need for this in C++. The
usage you have is simply more complicated than either of the other
solutions, and less understandable for the average C++ programmer.

Bill Kempf


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk