Logo Search packages:      
Sourcecode: passage version File versions  Download package

Semaphore.h

/*
 * Modification History
 *
 * 2001-January-11            Jason Rohrer
 * Created.
 *
 * 2001-January-11            Jason Rohrer
 * Added a willBlock() function. 
 *
 * 2001-February-24           Jason Rohrer
 * Fixed incorrect delete usage.
 *
 * 2002-February-11           Jason Rohrer
 * Fixed a mistake in the signal() comment.
 *
 * 2003-August-26   Jason Rohrer
 * Added support for timeouts on wait.
 *
 * 2003-December-28   Jason Rohrer
 * Fixed a bug in semaphore value when we timeout on wait.
 *
 * 2004-January-9   Jason Rohrer
 * Fixed a preprocessor error.
 */

#include "minorGems/common.h" 



#ifndef SEMAPHORE_CLASS_INCLUDED
#define SEMAPHORE_CLASS_INCLUDED

#include "MutexLock.h"
#include "BinarySemaphore.h"


/**
 * General semaphore with an unbounded value.
 *
 * This class uses BinarySemaphores to implement general semaphores,
 * so it relies on platform-specific BinarySemaphore implementations, 
 * but this class itself is platform-independent.
 *
 * @author Jason Rohrer
 */
00046 class Semaphore {

      public:
            
            /**
             * Constructs a semaphore.
             *
             * @param inStartingValue the starting value for this semaphore.
             *   Defaults to 0 if unspecified.
             */
            Semaphore( int inStartingValue = 0 );
            
            ~Semaphore();
            
            
            /**
             * If this semaphore's current value is 0, then this call blocks 
             * on this semaphore until signal() is called by another thread.
             * If this semaphore's value is >0, then it is decremented by this
         * call.
         *
         * @param inTimeoutInMilliseconds the maximum time to wait in
         *   milliseconds, or -1 to wait forever.  Defaults to -1.
         *
         * @return 1 if the semaphore was signaled, or 0 if it timed out.
             */
            int wait( int inTimeoutInMilliseconds = -1 );
        
            
            
            /**
             * If a thread is waiting on this semaphore, then the thread
             * becomes unblocked.
             * If no thread is waiting, then the semaphore is incremented.
             */
            void signal();

            
            /**
             * Returns true if a call to wait would have blocked.
             */
            char willBlock();


      private:
            
            // starts at 0
            int mSemaphoreValue;
            
            // mutex semaphore starts at 1
            BinarySemaphore *mMutexSemaphore;
            // blocking semaphore starts at 0
            BinarySemaphore *mBlockingSemaphore;
      };



00103 inline Semaphore::Semaphore( int inStartingValue )
      : mSemaphoreValue( inStartingValue ), 
      mMutexSemaphore( new BinarySemaphore() ),
      mBlockingSemaphore(  new BinarySemaphore() ) {
      
      // increment the mutex semaphore to 1
      mMutexSemaphore->signal();
      }
      
      
      
inline Semaphore::~Semaphore() {
      delete mMutexSemaphore;
      delete mBlockingSemaphore;
      }
      
      
      
00121 inline int Semaphore::wait( int inTimeoutInMilliseconds ) {
    int returnValue;
    // this implementation copied from _Operating System Concepts_, p. 172
      
      // lock the mutex
      mMutexSemaphore->wait();
      // decrement the semaphore
      mSemaphoreValue--;
      if( mSemaphoreValue < 0 ) {
            // we should block
            
            // release the mutex
            mMutexSemaphore->signal();
            
            // block
            returnValue = mBlockingSemaphore->wait( inTimeoutInMilliseconds );

        if( returnValue != 1 ) {
            // timed out

            // increment the semaphore, since we never got signaled
            // lock the mutex
            mMutexSemaphore->wait();
            mSemaphoreValue++;

            // we will unlock the mutex below
            }
            }
    else {
        returnValue = 1;
        }
      
      // release the mutex
      // ( if we were signaled, then the signaller left the mutex locked )
    // ( if we timed out, then we re-locked the mutex above )
      mMutexSemaphore->signal();

    return returnValue;
      }
      
      
      
00163 inline char Semaphore::willBlock() {
      char returnValue = false;
      
      // lock the mutex
      mMutexSemaphore->wait();

      // check if we will block
      if( mSemaphoreValue <= 0 ) {
            returnValue = true;
            }
      
      // release the mutex
      mMutexSemaphore->signal();
      
      return returnValue;
      }
      
      
      
00182 inline void Semaphore::signal() {
      // lock the mutex
      mMutexSemaphore->wait();
      // increment the semaphore
      mSemaphoreValue++;
      if( mSemaphoreValue <= 0 ) {
            // we need to wake up a waiting thread
            mBlockingSemaphore->signal();
            // let the waiting thread unlock the mutex
            }
      else {
            // no threads are waiting, so we need to unlock the mutex
            mMutexSemaphore->signal();
            }
      }
      
      
      

#endif

Generated by  Doxygen 1.6.0   Back to index