Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2001-08-07 14:04:51


> 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.


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