Fawkes API
Fawkes Development Version
|
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