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 Mutex::Mutex() 00059 { 00060 mutex_data = new MutexData(); 00061 pthread_mutex_init(&(mutex_data->mutex), NULL); 00062 } 00063 00064 /** Destructor */ 00065 Mutex::~Mutex() 00066 { 00067 pthread_mutex_destroy(&(mutex_data->mutex)); 00068 delete mutex_data; 00069 mutex_data = NULL; 00070 } 00071 00072 00073 /** Lock this mutex. 00074 * A call to lock() will block until the lock on the mutex could be aquired. 00075 * If you want to avoid see consider using try_lock(). 00076 */ 00077 void 00078 Mutex::lock() 00079 { 00080 int err = 0; 00081 if ( (err = pthread_mutex_lock(&(mutex_data->mutex))) != 0 ) { 00082 throw Exception(err, "Failed to aquire lock for thread %s", Thread::current_thread()->name()); 00083 } 00084 #ifdef DEBUG_THREADING 00085 // do not switch order, lock holder must be protected with this mutex! 00086 mutex_data->set_lock_holder(); 00087 #endif 00088 } 00089 00090 00091 /** Tries to lock the mutex. 00092 * This can also be used to check if a mutex is locked. The code for this 00093 * can be: 00094 * 00095 * @code 00096 * bool locked = false; 00097 * if ( mutex->try_lock() ) { 00098 * mutex->unlock(); 00099 * locked = true; 00100 * } 00101 * @endcode 00102 * 00103 * This cannot be implemented in Mutex in a locked() method since this 00104 * would lead to race conditions in many situations. 00105 * 00106 * @return true, if the mutex could be locked, false otherwise. 00107 */ 00108 bool 00109 Mutex::try_lock() 00110 { 00111 if (pthread_mutex_trylock(&(mutex_data->mutex)) == 0) { 00112 #ifdef DEBUG_THREADING 00113 mutex_data->set_lock_holder(); 00114 #endif 00115 return true; 00116 } else { 00117 return false; 00118 } 00119 } 00120 00121 00122 /** Unlock the mutex. */ 00123 void 00124 Mutex::unlock() 00125 { 00126 #ifdef DEBUG_THREADING 00127 mutex_data->unset_lock_holder(); 00128 // do not switch order, lock holder must be protected with this mutex! 00129 #endif 00130 pthread_mutex_unlock(&(mutex_data->mutex)); 00131 } 00132 00133 00134 /** Shortly stop by at the mutex. 00135 * This will just lock and unlock the mutex. It is equivalent to 00136 * @code 00137 * mutex->lock(); 00138 * mutex->unlock(); 00139 * @endcode 00140 * This can be handy if you have to protect starvation and just have a stop-by 00141 * mutex. 00142 */ 00143 void 00144 Mutex::stopby() 00145 { 00146 pthread_mutex_lock(&(mutex_data->mutex)); 00147 pthread_mutex_unlock(&(mutex_data->mutex)); 00148 } 00149 00150 00151 } // end namespace fawkes