LoCondition.H

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: */
Generated on Sun May 8 08:05:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3