/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2000-2002, Eric Crahen, See LGPL.TXT for details
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  SUNY @ Buffalo, hereby disclaims all copyright interest in the
 *  ZThreads library written by Eric Crahen
 */

#ifndef __ZTGUARD_H__
#define __ZTGUARD_H__

#include "zthread/ZThread.h"
#include "zthread/SynchronizationExceptions.h"

namespace ZThread { 

/**
 * @class Guard
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-02-24T09:25:13-0500>
 * @version 1.2.1
 *
 * Scoped locking utility. This template class can be given a Lockable
 * synchronization object and can 'Guard' or serialize access to 
 * that method.
 *  
 * For instance, consider a case in which a class or program have a  
 * Mutex object associated with it. Access can be serialized with a 
 * Guard as shown below.
 *
 * @code
 *
 * Mutex _mtx;
 * void guarded() {
 * 
 *    Guard<Mutex> g(_mtx);
 *
 * }
 *
 * @endcode
 *
 * The Guard will lock the synchronization object when it is created and 
 * automatically unlock it when it goes out of scope. This eliminates 
 * common mistakes like forgetting to unlock your mutex.
 *
 * An alternative to the above example would be 
 *
 * @code
 *
 * void guarded() {
 *
 *     (Guard<Mutex>)(_mtx);
 *
 * }
 *
 * @endcode
 *
 * HOWEVER; using a Guard in this method is dangerous. Depending on your
 * compiler an anonymous variable like this can go out of scope immediately
 * which can result in unexpected behavior. - This is the case with MSVC
 * and was the reason for introducing assertions into the Win32_MutexImpl
 * to track this problem down
 *
 */
template <class LOCK>
class ZTHREAD_API Guard {
  
  private:
  LOCK &_lock;
  
  // Prevent unwanted initialization
  Guard(const LOCK &);
  LOCK& operator = (const LOCK&);
  
  public:
  /**
   * Lock a given Lockable object with the creation of this Guard
   * 
   * @param LOCK& reference to a Lockable object
   */
  inline Guard(LOCK& l) : _lock(l) {

    _lock.acquire();

  };
  
  /**
   * Lock a given Lockable object with the tryAcquire function
   *
   * @param LOCK& reference to a Lockable object
   * @param unsigned long - milisecond timeout
   *
   * @exception Timeout_Exception - thrown if the tryAcquire operation
   * times out
   */
  inline Guard(LOCK& l, unsigned long timeout) 
    throw(Synchronization_Exception) : _lock(l) {

    if(!_lock.tryAcquire(timeout))
      throw Timeout_Exception();

  };


  /**
   * Unlock a given Lockable object with the destruction of this Guard
   */
  inline ~Guard() 
    throw() {
    
    try {
      _lock.release();
    }
    catch (...) {
    }
    
  };
  
}; /* Guard */

};
#endif







