00001 /** 00002 \file Robots/LoBot/misc/LoCondition.H 00003 \brief An object-oriented wrapper around pthreads condition variables. 00004 */ 00005 00006 // //////////////////////////////////////////////////////////////////// // 00007 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00008 // by the University of Southern California (USC) and the iLab at USC. // 00009 // See http://iLab.usc.edu for information about this project. // 00010 // //////////////////////////////////////////////////////////////////// // 00011 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00012 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00013 // in Visual Environments, and Applications'' by Christof Koch and // 00014 // Laurent Itti, California Institute of Technology, 2001 (patent // 00015 // pending; application number 09/912,225 filed July 23, 2001; see // 00016 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00017 // //////////////////////////////////////////////////////////////////// // 00018 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00019 // // 00020 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00021 // redistribute it and/or modify it under the terms of the GNU General // 00022 // Public License as published by the Free Software Foundation; either // 00023 // version 2 of the License, or (at your option) any later version. // 00024 // // 00025 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00026 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00027 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00028 // PURPOSE. See the GNU General Public License for more details. // 00029 // // 00030 // You should have received a copy of the GNU General Public License // 00031 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00032 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00033 // Boston, MA 02111-1307 USA. // 00034 // //////////////////////////////////////////////////////////////////// // 00035 // 00036 // Primary maintainer for this file: mviswana usc edu 00037 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/thread/LoCondition.H $ 00038 // $Id: LoCondition.H 13523 2010-06-07 00:22:03Z mviswana $ 00039 // 00040 00041 #ifndef LOBOT_CONDITION_VARIABLE_DOT_H 00042 #define LOBOT_CONDITION_VARIABLE_DOT_H 00043 00044 //------------------------------ HEADERS -------------------------------- 00045 00046 // POSIX threads 00047 #ifdef INVT_HAVE_LIBPTHREAD 00048 00049 #include <pthread.h> 00050 00051 #else // fake pthreads API to allow builds to succeed 00052 00053 typedef int pthread_mutex_t ; 00054 typedef int pthread_cond_t ; 00055 typedef struct {} timeval ; 00056 typedef struct {} timespec ; 00057 00058 static void pthread_mutex_lock (pthread_mutex_t*) {} 00059 static void pthread_mutex_unlock(pthread_mutex_t*) {} 00060 00061 static void pthread_cond_wait (pthread_cond_t*, pthread_mutex_t*) {} 00062 static void pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, 00063 struct timespec*) {} 00064 00065 static void pthread_cond_signal (pthread_cond_t*) {} 00066 static void pthread_cond_broadcast(pthread_cond_t*) {} 00067 00068 #endif 00069 00070 // Standard Unix/C headers 00071 #include <sys/time.h> 00072 #include <errno.h> 00073 00074 //----------------------------- NAMESPACE ------------------------------- 00075 00076 namespace lobot { 00077 00078 //------------------------- CLASS DEFINITION ---------------------------- 00079 00080 /** 00081 \class lobot::Condition 00082 \brief A simple encapsulation of pthread condition variables. 00083 */ 00084 class Condition { 00085 // Prevent copy and assignment 00086 Condition(const Condition&) ; 00087 Condition& operator=(const Condition&) ; 00088 00089 /// A condition variable is always associated with a mutex. 00090 pthread_mutex_t m_mutex ; 00091 00092 /// The underlying pthread condition variable. 00093 pthread_cond_t m_cond ; 00094 00095 /// A helper class to lock and unlock the mutex automatically so that 00096 /// exceptions in client code don't result in the mutex remaining 00097 /// locked. The constructor locks the mutex and the destructor unlocks 00098 /// it. This class is meant to be instantiated on the stack to ensure 00099 /// that the desctructor gets called when the variable goes out of 00100 /// scope. Thus, no special processing will be needed in case of 00101 /// exceptions in client code; that is, the Condition class's 00102 /// functions don't need to explicitly catch and rethrow exceptions 00103 /// and take care of unlocking the mutex in the exception handlers. 00104 /// 00105 /// DEVNOTE: We could reuse lobot::AutoMutex here instead of 00106 /// reimplementing its functionality. However, it seemed like a good 00107 /// idea to keep the Condition class entirely self-contained so that 00108 /// it could be reused without requiring clients to forcibly also rely 00109 /// on the lobot Mutex encapsulation. Instead, this class relies only 00110 /// and solely on pthreads. 00111 class AutoMutex { 00112 pthread_mutex_t& mutex ; 00113 public: 00114 AutoMutex(pthread_mutex_t&) ; 00115 ~AutoMutex() ; 00116 } ; 00117 00118 public: 00119 /// Default constructor: sets up the pthread condition variable. 00120 Condition() ; 00121 00122 /// This function can be used by clients to wait on this condition 00123 /// variable. The wait is forever, i.e., the calling thread will wait 00124 /// until the condition is signaled by some other thread. 00125 /// 00126 /// This function expects to be passed a predicate function or 00127 /// function object that should return true if the shared data being 00128 /// waited on is in the desired state, i.e., the state in which the 00129 /// condition variable is flagged as being satisfied. If the predicate 00130 /// returns false, the calling thread will continue to wait. 00131 /// 00132 /// Thus, this function will block the calling thread until the 00133 /// predicate returns true. 00134 /// 00135 /// Basically, this function implements the usual wait pattern to be 00136 /// applied for pthread condition variables so that clients need only 00137 /// implement the actual test required to decide whether the condition 00138 /// variable is satisfied or not. 00139 template<typename F> void wait(F pred) ; 00140 00141 /// This function can be used by clients to wait on this condition 00142 /// variable. The wait is timed, i.e., the calling thread will wait 00143 /// until either the condition is signaled by some other thread or 00144 /// until the wait times out. 00145 /// 00146 /// This function expects to be passed a predicate function or 00147 /// function object that should return true if the shared data being 00148 /// waited on is in the desired state, i.e., the state in which the 00149 /// condition variable is flagged as being satisfied. If the predicate 00150 /// returns false, the calling thread will continue to wait. 00151 /// 00152 /// Additionally, the function should be passed a timeout value in 00153 /// milliseconds. 00154 /// 00155 /// Thus, this function will block the calling thread until the 00156 /// client-supplied test condition becomes true or until the timeout 00157 /// is exceeded. 00158 /// 00159 /// This function will return true to indicate that the wait completed 00160 /// successfully, i.e., the condition being waited on is signaled. A 00161 /// false return value indicates that the wait timed out. 00162 /// 00163 /// Basically, this function implements the usual timed-wait pattern 00164 /// to be applied for pthread condition variables so that clients 00165 /// need only implement the actual test required to decide whether the 00166 /// condition variable is satisfied or not. 00167 template<typename F> bool wait(F pred, int timeout) ; 00168 00169 /// This function signals any one thread waiting on this condition 00170 /// variable that the condition has been satisfied. 00171 /// 00172 /// The function expects to be passed a predicate function or function 00173 /// object that should return true to indicate that the shared data 00174 /// being waited on is in the desired state, i.e., the state in which 00175 /// the condition variable is flagged as being satisfied. If the 00176 /// predicate returns false, the calling thread will not signal the 00177 /// condition variable and waiting threads will continue to wait. 00178 /// 00179 /// Additionally, the predicate function/object should also perform 00180 /// the necessary operations to actually bring the shared data into 00181 /// the state in which the condition variable can be signaled. 00182 /// 00183 /// Basically, this function implements the usual pthread signaling 00184 /// pattern for condition variables so that clients need only 00185 /// implement the actual test required to decide whether the condition 00186 /// variable is satisfied or not. 00187 template<typename F> void signal(F pred) ; 00188 00189 /// This function signals all threads waiting on this condition 00190 /// variable that the condition has been satisfied. 00191 /// 00192 /// The function expects to be passed a predicate function or function 00193 /// object that should return true to indicate that the shared data 00194 /// being waited on is in the desired state, i.e., the state in which 00195 /// the condition variable is flagged as being satisfied. If the 00196 /// predicate returns false, the calling thread will not signal the 00197 /// condition variable and waiting threads will continue to wait. 00198 /// 00199 /// Additionally, the predicate function/object should also perform 00200 /// the necessary operations to actually bring the shared data into 00201 /// the state in which the condition variable can be signaled. 00202 /// 00203 /// Basically, this function implements the usual pthread signaling 00204 /// pattern for condition variables so that clients need only 00205 /// implement the actual test required to decide whether the condition 00206 /// variable is satisfied or not. 00207 template<typename F> void broadcast(F pred) ; 00208 00209 /// This function allows clients to execute some function under the 00210 /// protection of the mutex associated with this condition variable. 00211 /// The condition variable itself is not involved; only its associated 00212 /// mutex comes into play. The mutex is locked prior to calling the 00213 /// client-supplied function or funcion object and unlocked after it. 00214 template<typename F> void protect(F func) ; 00215 00216 /// Clean-up: release the pthread condition variable and its 00217 /// associated mutex. 00218 ~Condition() ; 00219 } ; 00220 00221 //--------------------- TEMPLATE MEMBER FUNCTIONS ----------------------- 00222 00223 #ifdef INVT_HAVE_LIBPTHREAD 00224 00225 //------------------------------ WAITING -------------------------------- 00226 00227 // Wait on condition variable until client-supplied test becomes true 00228 template<typename F> 00229 void Condition::wait(F pred) 00230 { 00231 AutoMutex M(m_mutex) ; 00232 while (! pred()) 00233 pthread_cond_wait(&m_cond, &m_mutex) ; 00234 } 00235 00236 // Timed-wait on condition variable until client-supplied test becomes true 00237 template<typename F> 00238 bool Condition::wait(F pred, int timeout_ms) 00239 { 00240 AutoMutex M(m_mutex) ; 00241 00242 // pthread_cond_timedwait() needs an absolute time to wait until. So 00243 // we need to express the supplied timeout delay as the current time 00244 // plus delay. 00245 struct timeval now ; 00246 if (gettimeofday(&now, 0) == -1) // error getting current time 00247 return false ; 00248 00249 // Convert current time and timeout delay to nanoseconds and add them 00250 // all to yield desired wait time for pthread_cond_timedwait(). 00251 long long to = static_cast<long long>(now.tv_sec) * 1000000000L 00252 + static_cast<long long>(now.tv_usec) * 1000L 00253 + static_cast<long long>(timeout_ms) * 1000000L ; 00254 00255 // Express absolute timeout time in units required by 00256 // pthread_cond_timedwait(): seconds + nanoseconds. 00257 struct timespec timeout ; 00258 timeout.tv_sec = static_cast<time_t>(to/1000000000L) ; 00259 timeout.tv_nsec = static_cast<long>(to % 1000000000L) ; 00260 00261 // Now, wait until client-supplied test condition becomes true or 00262 // until timeout expires... 00263 int timed_out = 0 ; 00264 while (! pred() && timed_out != ETIMEDOUT) 00265 timed_out = pthread_cond_timedwait(&m_cond, &m_mutex, &timeout) ; 00266 return (timed_out != ETIMEDOUT); 00267 } 00268 00269 //----------------------------- SIGNALING ------------------------------- 00270 00271 // Wake up any one thread waiting on condition 00272 template<typename F> 00273 void Condition::signal(F pred) 00274 { 00275 AutoMutex M(m_mutex) ; 00276 if (pred()) 00277 pthread_cond_signal(&m_cond) ; 00278 } 00279 00280 // Wake up all threads waiting on condition 00281 template<typename F> 00282 void Condition::broadcast(F pred) 00283 { 00284 AutoMutex M(m_mutex) ; 00285 if (pred()) 00286 pthread_cond_broadcast(&m_cond) ; 00287 } 00288 00289 //------------------------ PROTECTED EXECUTION -------------------------- 00290 00291 // Execute client-supplied function under the protection of the condition 00292 // variable's mutex. 00293 template<typename F> 00294 void Condition::protect(F func) 00295 { 00296 AutoMutex M(m_mutex) ; 00297 func() ; 00298 } 00299 00300 //----------------------------- EMPTY API ------------------------------- 00301 00302 #else // pthreads missing 00303 00304 template<typename F> void Condition::wait(F){} 00305 template<typename F> bool Condition::wait(F, int){return false ;} 00306 template<typename F> void Condition::signal(F){} 00307 template<typename F> void Condition::broadcast(F){} 00308 template<typename F> void Condition::protect(F){} 00309 00310 #endif 00311 00312 //----------------------------------------------------------------------- 00313 00314 } // end of namespace encapsulating this file's definitions 00315 00316 #endif 00317 00318 /* So things look consistent in everyone's emacs... */ 00319 /* Local Variables: */ 00320 /* indent-tabs-mode: nil */ 00321 /* End: */