Fawkes API  Fawkes Development Version
mutex.cpp
00001 
00002 /***************************************************************************
00003  *  mutex.cpp - implementation of mutex, based on pthreads
00004  *
00005  *  Generated: Thu Sep 14 17:03:57 2006
00006  *  Copyright  2006  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <core/threading/mutex.h>
00025 #include <core/threading/mutex_data.h>
00026 #include <core/threading/thread.h>
00027 #include <core/exception.h>
00028 
00029 #include <pthread.h>
00030 
00031 namespace fawkes {
00032 
00033 /** @class Mutex core/threading/mutex.h
00034  * Mutex mutual exclusion lock.
00035  * This class is used in a multi-threading environment to lock access to
00036  * resources. This is needed to prevent two threads from modifying a value
00037  * at the same time or to prevent a thread from getting a dirty copy of
00038  * a piece of data (the reader reads while a writer is writing, this could
00039  * leave the data in a state where the reader reads half of the new and half
00040  * of the old data).
00041  *
00042  * As a rule of thumb you should lock the mutex as short as possible and as
00043  * long as needed. Locking the mutex too long will lead in a bad performance
00044  * of the multi-threaded application because many threads are waiting for
00045  * the lock and are not doing anything useful.
00046  * If you do not lock enough code (and so serialize it) it will cause pain
00047  * and errors.
00048  *
00049  * @ingroup Threading
00050  * @ingroup FCL
00051  * @see example_mutex_count.cpp
00052  *
00053  * @author Tim Niemueller
00054  */
00055 
00056 
00057 /** Constructor.
00058  * @param type mutex type 
00059  */
00060 Mutex::Mutex(Type type)
00061 {
00062   mutex_data = new MutexData();
00063 
00064   pthread_mutexattr_t attr;
00065   pthread_mutexattr_init(&attr);
00066   if (type == RECURSIVE) {
00067     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
00068   } else {
00069     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
00070   }
00071 
00072   pthread_mutex_init(&(mutex_data->mutex), &attr);
00073 }
00074 
00075 /** Destructor */
00076 Mutex::~Mutex()
00077 {
00078   pthread_mutex_destroy(&(mutex_data->mutex));
00079   delete mutex_data;
00080   mutex_data = NULL;
00081 }
00082 
00083 
00084 /** Lock this mutex.
00085  * A call to lock() will block until the lock on the mutex could be aquired.
00086  * If you want to avoid see consider using try_lock().
00087  */
00088 void
00089 Mutex::lock()
00090 {
00091   int err = 0;
00092   if ( (err = pthread_mutex_lock(&(mutex_data->mutex))) != 0 ) {
00093     throw Exception(err, "Failed to aquire lock for thread %s", Thread::current_thread()->name());
00094   }
00095 #ifdef DEBUG_THREADING
00096   // do not switch order, lock holder must be protected with this mutex!
00097   mutex_data->set_lock_holder();
00098 #endif
00099 }
00100 
00101 
00102 /** Tries to lock the mutex.
00103  * This can also be used to check if a mutex is locked. The code for this
00104  * can be:
00105  *
00106  * @code
00107  * bool locked = false;
00108  * if ( mutex->try_lock() ) {
00109  *   mutex->unlock();
00110  *   locked = true;
00111  * }
00112  * @endcode
00113  *
00114  * This cannot be implemented in Mutex in a locked() method since this
00115  * would lead to race conditions in many situations.
00116  *
00117  * @return true, if the mutex could be locked, false otherwise.
00118  */
00119 bool
00120 Mutex::try_lock()
00121 {
00122   if (pthread_mutex_trylock(&(mutex_data->mutex)) == 0) {
00123 #ifdef DEBUG_THREADING
00124     mutex_data->set_lock_holder();
00125 #endif
00126     return true;
00127   } else {
00128     return false;
00129   }
00130 }
00131 
00132 
00133 /** Unlock the mutex. */
00134 void
00135 Mutex::unlock()
00136 {
00137 #ifdef DEBUG_THREADING
00138   mutex_data->unset_lock_holder();
00139   // do not switch order, lock holder must be protected with this mutex!
00140 #endif
00141   pthread_mutex_unlock(&(mutex_data->mutex));
00142 }
00143 
00144 
00145 /** Shortly stop by at the mutex.
00146  * This will just lock and unlock the mutex. It is equivalent to
00147  * @code
00148  *   mutex->lock();
00149  *   mutex->unlock();
00150  * @endcode
00151  * This can be handy if you have to protect starvation and just have a stop-by
00152  * mutex.
00153  */
00154 void
00155 Mutex::stopby()
00156 {
00157   pthread_mutex_lock(&(mutex_data->mutex));
00158   pthread_mutex_unlock(&(mutex_data->mutex));
00159 }
00160 
00161 
00162 } // end namespace fawkes