LoThread.H

00001 /**
00002    \file  Robots/LoBot/misc/LoThread.H
00003    \brief A thin wrapper around some parts of the pthreads creation and
00004    management API.
00005 
00006    This file defines a base class, viz., lobot::Thread, for creating
00007    threads to handle different sensorimotor operations within the
00008    Robolocust system. Robolocust modules that need to create new threads
00009    should use this class rather than the raw pthreads API.
00010 
00011    However, it should be noted that lobot::Thread is only for creating
00012    threads and some basic thread management related tasks. Thus, users
00013    have to fall back on raw pthreads for mutexes, condition variables and
00014    other such paraphernalia.
00015 */
00016 
00017 // //////////////////////////////////////////////////////////////////// //
00018 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00019 // by the University of Southern California (USC) and the iLab at USC.  //
00020 // See http://iLab.usc.edu for information about this project.          //
00021 // //////////////////////////////////////////////////////////////////// //
00022 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00023 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00024 // in Visual Environments, and Applications'' by Christof Koch and      //
00025 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00026 // pending; application number 09/912,225 filed July 23, 2001; see      //
00027 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00028 // //////////////////////////////////////////////////////////////////// //
00029 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00030 //                                                                      //
00031 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00032 // redistribute it and/or modify it under the terms of the GNU General  //
00033 // Public License as published by the Free Software Foundation; either  //
00034 // version 2 of the License, or (at your option) any later version.     //
00035 //                                                                      //
00036 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00037 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00038 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00039 // PURPOSE.  See the GNU General Public License for more details.       //
00040 //                                                                      //
00041 // You should have received a copy of the GNU General Public License    //
00042 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00043 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00044 // Boston, MA 02111-1307 USA.                                           //
00045 // //////////////////////////////////////////////////////////////////// //
00046 //
00047 // Primary maintainer for this file: mviswana usc edu
00048 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/thread/LoThread.H $
00049 // $Id: LoThread.H 13521 2010-06-06 14:23:03Z mviswana $
00050 //
00051 
00052 #ifndef LOBOT_THREAD_DOT_H
00053 #define LOBOT_THREAD_DOT_H
00054 
00055 //------------------------------ HEADERS --------------------------------
00056 
00057 // POSIX threads
00058 #ifdef INVT_HAVE_LIBPTHREAD
00059 
00060 #include <pthread.h>
00061 
00062 #else // fake pthreads API to allow builds to succeed
00063 
00064 typedef int pthread_t ;
00065 typedef int pthread_mutex_t ;
00066 typedef int pthread_cond_t ;
00067 
00068 #endif
00069 
00070 // Standard C++ headers
00071 #include <string>
00072 
00073 //----------------------------- NAMESPACE -------------------------------
00074 
00075 namespace lobot {
00076 
00077 //------------------------- CLASS DEFINITION ----------------------------
00078 
00079 /**
00080    \class lobot::Thread
00081    \brief An ABC for POSIX threads.
00082 
00083    lobot::Thread is an abstract base class for creating threads to handle
00084    different tasks within the Robolocust system. It wraps around some of
00085    the basic creation and management APIs of the POSIX threads library
00086    and provides some additional custom support on top of that.
00087 
00088    In terms of the additional custom support alluded to above,
00089    specifically, this class keeps track of the number of threads
00090    currently running and allows the main thread to wait for all the other
00091    threads to die with one convenient API.
00092 
00093    Robolocust modules that need to create new threads should use this
00094    class rather than the raw pthreads API. However, only some basic
00095    thread creation and management functions are implemented. This means
00096    that clients have to either fall back on the raw POSIX API or rely on
00097    some other wrapper classes for mutexes, condition variables, etc.
00098 
00099    To use this class, simply derive from it and define the run() method.
00100    Then, instantiating the derived class will take care of the mechanics
00101    of creating the thread, keeping track of it, etc.
00102 
00103    An important thing to keep in mind when using this class is that the
00104    threads it creates are detached, i.e., it is not possible for another
00105    thread to execute pthread_join() on the thread. This ensures that all
00106    thread resources are immediately cleaned up by the OS when the thread
00107    exits. Naturally, it also prevents other threads from joining with it.
00108 
00109    The rationale for this design choice is as follows: the Robolocust
00110    system maintains a central shutdown object that signals all the
00111    threads that it's time to wind-up. Each Robolocust thread is required
00112    to monitor the state of this shutdown object in its main loop and take
00113    appropriate action to gracefully kill itself when the shutdown object
00114    is in the signaled state. Additionally, when shutdown is signaled, the
00115    main thread waits for all the other threads to die and then exits the
00116    application. Thus, there is no need for any thread to wait for another
00117    by joining with it.
00118 
00119    NOTE: This class does not prevent clients from creating instances on
00120    the stack (i.e., as local variables). However, doing that would
00121    generally be a Bad Idea because when the local object goes out of
00122    scope, its run() method will no longer be available, which, most
00123    likely, will cause all hell to break loose.
00124 
00125    DEVNOTE: We could use the named constructor idiom to require clients
00126    to always create Thread objects with the new operator. However, that
00127    precludes using this class in conjunction with lobot::singleton, which
00128    is why we don't enforce the do-not-create-on-stack policy.
00129 */
00130 class Thread {
00131    // Prevent copy and assignment
00132    Thread(const Thread&) ;
00133    Thread& operator=(const Thread&) ;
00134 
00135 private:
00136    /// Every thread has to have an ID and a name.
00137    //@{
00138    pthread_t   m_id ;
00139    std::string m_name ;
00140    //@}
00141 
00142 public:
00143    /// Return this thread's ID.
00144    pthread_t id() const {return m_id ;}
00145 
00146    /// Return this thread's name.
00147    const std::string& name() const {return m_name ;}
00148 
00149    /// Check if the thread is actually running.
00150    bool running() const {return m_id != 0 ;}
00151 
00152 protected:
00153    /// A protected constructor because clients should not be able to
00154    /// directly instantiate this class.
00155    Thread() ;
00156 
00157    /// Creating a new thread object doesn't automatically start the
00158    /// thread running. Derived classes *must* call this method in the
00159    /// body of their constructors (usually, towards the end). The reason
00160    /// for this two-step procedure is due to the fact that the thread
00161    /// function implemented in this base class calls the run() method in
00162    /// the derived class. For this to work properly, the derived class
00163    /// object must be fully constructed with its v-table setup for
00164    /// action. If we were to start the new thread running in this class's
00165    /// constructor, it can happen that Thread::thread_func() will crash
00166    /// when it attempts to invoke the pure virtual run() method.
00167    ///
00168    /// Therefore, *all* derived class constructors *must* include a call
00169    /// to Thread::start(). By the time we get into a constructor's body,
00170    /// we can be assured that the object is fully constructed and its
00171    /// v-table properly setup. This ensures that Thread::thread_func()
00172    /// will be able to use the virtual function mechanism to call into
00173    /// the derived class's run() method.
00174    ///
00175    /// Note, however, that client modules do not see this two-step thread
00176    /// creation procedure. A client module simply creates an instance of
00177    /// a Thread subclass without having to fuss around with anything
00178    /// else. Once the instance is created, the thread will automatically
00179    /// start running. The onus here is on subclasses to ensure that this
00180    /// automatic thread creation and starting business actually works
00181    /// from the point of view of client modules.
00182    ///
00183    /// Usually, a derived class's run() method will implement some sort
00184    /// of "main" loop and when that loop exits, the run() method will
00185    /// return. However, in some situations, the main loop may be
00186    /// implemented externally (e.g., glutMainLoop()). Threads that
00187    /// implement run() methods that don't return normally should pass
00188    /// false as the second parameter to Thread::start().
00189    void start(const std::string& name,
00190               bool thread_func_returns_normally = true) ;
00191 
00192 private:
00193    /// This is the thread function for each thread. In this base class,
00194    /// it simply serves as the mechanics for getting the pthreads API to
00195    /// work properly without burdening derived/client classes with the
00196    /// gory details. Instead, derived classes need only derive from this
00197    /// one and then define the run() method.
00198    static void* thread_func(void* arg) ;
00199 
00200    /// Normally, a thread's run() method will return normally, i.e., back
00201    /// to the thread_func. This allows thread_func() to keep track of the
00202    /// number of threads currently running.
00203    ///
00204    /// However, in some cases, the run() method may not return to the
00205    /// thread_func. For example, a thread that calls glutMainLoop() will
00206    /// have to terminate itself using pthread_exit() rather than by
00207    /// falling out a of a loop because GLUT controls the thread's main
00208    /// loop and provides no direct means of exiting that loop.
00209    ///
00210    /// In such cases, thread_func_no_return() is used as the thread_func.
00211    /// The difference between this thread_func and the usual one is that
00212    /// it does not increment/decrement the thread count prior to and
00213    /// after the run() method call (because the run() method will never
00214    /// return control to it).
00215    ///
00216    /// What this means is that there may be more or less threads actually
00217    /// running than the count maintained in the Thread class. This is an
00218    /// unfortunate consequence of the run-method-not-returning-normally
00219    /// problem. However, it is necessary to have this mechanism in place
00220    /// to ensure that the Robolocust controller exits without any hassles
00221    /// when such threads are running. If we did not have this workaround
00222    /// in place, the main thread would wait for all threads to die; but
00223    /// thread count would never go down to zero because the run method of
00224    /// a thread whose main loop is implemented "externally" would never
00225    /// return, thus, causing the main thread to wait forever.
00226    ///
00227    /// Moral of the story: limit the number of threads that don't return
00228    /// normally from their run() methods. And, in such threads, be sure
00229    /// to pass false to the second parameter of the start() method.
00230    static void* thread_func_no_return(void* arg) ;
00231 
00232 public:
00233    /// This method implements the thread's custom processing. It must be
00234    /// defined by every subclass.
00235    virtual void run() = 0 ;
00236 
00237 private:
00238    /// This class keeps track of the number of extant threads with a
00239    /// simple shared counter.
00240    static int m_count ;
00241 
00242    /// Since the above counter can be accessed by multiple threads, we
00243    /// need a mutex to ensure serialized updates to the count.
00244    static pthread_mutex_t m_count_mutex ;
00245 
00246 public:
00247    /// Return the current number of extant threads.
00248    static int count() ;
00249 
00250 private:
00251    /// This class provides an API that allows the main thread to wait for
00252    /// all the other extant threads to die. This condition is signaled
00253    /// using a condition variable that is flagged when the count of
00254    /// extant threads reaches zero.
00255    static pthread_cond_t m_count_zero_condition ;
00256 
00257 public:
00258    /// Wait for all the extant threads to die.
00259    ///
00260    /// NOTE: This method is meant to be called *only* by the main thread.
00261    static void wait_all() ;
00262 
00263    /// Clean-up.
00264    virtual ~Thread() ;
00265 } ;
00266 
00267 //-----------------------------------------------------------------------
00268 
00269 } // end of namespace encapsulating this file's definitions
00270 
00271 #endif
00272 
00273 /* So things look consistent in everyone's emacs... */
00274 /* Local Variables: */
00275 /* indent-tabs-mode: nil */
00276 /* End: */
Generated on Sun May 8 08:05:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3