ACE Tutorial 017
Using the ACE_Barrier synch object


The Barrier class used by the test task is a simple wrapper around ACE_Barrier. One of the things about ACE_Barrier is that you have to tell it how many threads it will be managing. Since that number usually isn't known when you create your Task derivative, you have to dynamically allocate the ACE_Barrier. My Barrier wrapper takes care of that for you and even provides for a clean way to delete the ACE_Barrier instance if you want to save a few bytes.

An interesting extension of this Barrier class would be to wrap it up in a smart pointer. You could then have the Barrier destructor invoke wait() as a now-protected method. The result would allow you to treat the Barrier object almost as a "synchronization guard".


// $Id$

#ifndef BARRIER_H
#define BARRIER_H

#include "ace/Synch.h"
#include "ace/Atomic_Op.h"

/* Barrier is a simple wrapper for the ACE_Barrier synchronization
   class.  The ACE_Barrier is already pretty easy to use but I thought
   I'd wrap it up to create just a bit more abstraction at the
   application level.  */

class Barrier
{
public:
  // Basic constructor and destructor.  If you only need to synch the
  // start of your threads, you can safely delete your Barrier object
  // after invoking done().  Of course, you should be careful to only
  // delete the object once!
  Barrier (void);
  ~Barrier (void);

  // Set and get the number of threads that the barrier will manage.
  // If you add or remove threads to your application at run-time you
  // can use the mutator to reflect that change.  Note, however, that
  // you can only do that from the thread which first created the
  // Barrier.  (This is a limitation of my Barrier object, not the
  // ACE_Barrier.)  The optional _wait parameter will cause wait() to
  // be invoked if there is already a valid threads value.
  int threads (u_int threads, int wait = 0);
  u_int threads (void);

  // Wait for all threads to reach the point where this is invoked.
  // Because of the snappy way in which ACE_Barrier is implemented,
  // you can invoke these back-to-back with no ill-effects.
  int wait (void);

  // done() will invoke wait().  Before returning though, it will
  // delete the barrier_ pointer below to reclaim some memory.
  int done (void);

  // Reset the owning thread of the barrier.
  void owner( ACE_thread_t _owner );

protected:
  // The number of threads we're synching
  ACE_Atomic_Op<ACE_Mutex, u_int> threads_;

  // The ACE_Barrier that does all of the work
  ACE_Barrier *barrier_;

  // If we mutate the number of threads we have to do some black magic
  // to make sure there isn't a memory leak.  These two member
  // variables are a part of that magic.
  ACE_Barrier *new_barrier_;
  ACE_Mutex    barrier_mutex_;

  // The thread which created the Barrier in the first place.  Only
  // this thread can change the threads_ value.
  ACE_thread_t owner_;

  // An internal method that constructs the barrier_ as needed.
  int make_barrier (int wait);
};

#endif /* BARRIER_H */


[Tutorial Index] [Continue This Tutorial]