Equalizer 1.0

thread.h

00001 
00002 /* Copyright (c) 2005-2011, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #ifndef COBASE_THREAD_H
00019 #define COBASE_THREAD_H
00020 
00021 #include <co/base/api.h>      // COBASE_API definition
00022 #include <co/base/debug.h>    // debug macros in thread-safety checks
00023 #include <co/base/lock.h>     // member
00024 #include <co/base/monitor.h>  // member
00025 #include <co/base/threadID.h> // member
00026 
00027 #include <ostream>
00028 
00029 namespace co
00030 {
00031 namespace base
00032 {
00033     class ExecutionListener;
00034 
00036     class Thread 
00037     {
00038     public:
00040         COBASE_API Thread();
00041 
00043         COBASE_API virtual ~Thread();
00044 
00056         COBASE_API bool start();
00057 
00069         virtual bool init(){ return true; }
00070 
00079         virtual void run() = 0;
00080 
00089         COBASE_API virtual void exit();
00090 
00097         COBASE_API void cancel();
00098 
00105         COBASE_API bool join();
00106 
00116         bool isStopped() const { return ( _state == STATE_STOPPED ); }
00117 
00127         bool isRunning() const { return ( _state == STATE_RUNNING ); }
00128 
00136         COBASE_API bool isCurrent() const;
00137 
00144         COBASE_API static void addListener( ExecutionListener* listener );
00145 
00152         COBASE_API static bool removeListener( ExecutionListener* listener );
00153 
00155         COBASE_API static void removeAllListeners();
00156 
00158         COBASE_API static ThreadID getSelfThreadID();
00159 
00161         COBASE_API void untrack();
00162 
00164         COBASE_API static void yield();
00165 
00167         static void pinCurrentThread();
00168 
00170         COBASE_API static void setName( const std::string& name );
00171 
00172     private:
00173         ThreadID _id;
00174 
00176         enum State
00177         {
00178             STATE_STOPPED,
00179             STATE_STARTING, // start() in progress
00180             STATE_RUNNING,
00181             STATE_STOPPING  // child no longer active, join() not yet called
00182         };
00183 
00184         Monitor< State > _state;
00185 
00186         static void* runChild( void* arg );
00187         void        _runChild();
00188 
00189         void _installCleanupHandler();
00190 
00191         static void _notifyStarted();
00192         static void _notifyStopping();
00193         friend void _notifyStopping( void* ); 
00194 
00195         friend std::ostream& operator << ( std::ostream& os, const Thread* );
00196     };
00197 
00199     std::ostream& operator << ( std::ostream& os, const Thread* thread );
00200 
00201 // thread-safety checks
00202 // These checks are for development purposes, to check that certain objects are
00203 // properly used within the framework. Leaving them enabled during application
00204 // development may cause false positives, e.g., when threadsafety is ensured
00205 // outside of the objects by the application.
00206 
00207 #ifndef NDEBUG
00208 #  define EQ_CHECK_THREADSAFETY
00209 #endif
00210 
00212 #define EQ_TS_VAR( NAME )                                   \
00213 public:                                                     \
00214     struct NAME ## Struct                                   \
00215     {                                                       \
00216         NAME ## Struct ()                                   \
00217             : extMutex( false ), inRegion( false )          \
00218             {}                                              \
00219         mutable co::base::ThreadID id;                      \
00220         mutable std::string name;                           \
00221         bool extMutex;                                      \
00222         mutable bool inRegion;                              \
00223     } NAME;                                                 \
00224 private:
00225 
00226 #ifdef EQ_CHECK_THREADSAFETY
00227 #  define EQ_TS_RESET( NAME ) NAME.id = co::base::ThreadID::ZERO; 
00228 
00229 #  define EQ_TS_THREAD( NAME )                                          \
00230     {                                                                   \
00231         if( NAME.id == co::base::ThreadID::ZERO )                       \
00232         {                                                               \
00233             NAME.id = co::base::Thread::getSelfThreadID();              \
00234             NAME.name = co::base::Log::instance().getThreadName();      \
00235             EQVERB << "Functions for " << #NAME                         \
00236                    << " locked to this thread" << std::endl;            \
00237         }                                                               \
00238         if( !NAME.extMutex && NAME.id != co::base::Thread::getSelfThreadID( )) \
00239         {                                                               \
00240             EQERROR << "Threadsafety check for " << #NAME               \
00241                     << " failed on object of type "                     \
00242                     << co::base::className( this ) << ", thread "       \
00243                     << co::base::Thread::getSelfThreadID() << " ("      \
00244                     << co::base::Log::instance().getThreadName() << ") != " \
00245                     << NAME.id << " (" << NAME.name << ")" << std::endl; \
00246             EQABORT( "Non-threadsave code called from two threads" );   \
00247         }                                                               \
00248     }
00249 
00250 #  define EQ_TS_NOT_THREAD( NAME )                                      \
00251     {                                                                   \
00252         if( !NAME.extMutex && NAME.id != co::base::ThreadID::ZERO )     \
00253         {                                                               \
00254             if( NAME.id == co::base::Thread::getSelfThreadID( ))        \
00255             {                                                           \
00256                 EQERROR << "Threadsafety check for not " << #NAME       \
00257                         << " failed on object of type "                 \
00258                         << co::base::className( this ) << std::endl;    \
00259                 EQABORT( "Code called from wrong thread" );             \
00260             }                                                           \
00261         }                                                               \
00262     }
00263 
00265     template< typename T > class ScopedThreadCheck : public NonCopyable
00266     {
00267     public:
00268         explicit ScopedThreadCheck( const T& data )
00269                 : _data( data )
00270             {
00271                 EQASSERTINFO( !data.inRegion,
00272                               "Another thread already in critical region" );
00273                 data.inRegion = true;
00274             }
00275         ~ScopedThreadCheck() 
00276             {
00277                 EQASSERTINFO( _data.inRegion,
00278                               "Another thread was in critical region" );
00279                 _data.inRegion = false;
00280             }
00281     private:
00282         const T& _data;
00283     };
00286 # define EQ_TS_SCOPED( NAME ) \
00287     co::base::ScopedThreadCheck< NAME ## Struct > scoped ## NAME ## Check(NAME);
00288 
00289 #else
00290 #  define EQ_TS_RESET( NAME ) {}
00291 #  define EQ_TS_THREAD( NAME ) {}
00292 #  define EQ_TS_NOT_THREAD( NAME ) {}
00293 #  define EQ_TS_SCOPED( NAME ) {}
00294 #endif
00295 
00296 }
00297 }
00298 #endif //COBASE_THREAD_H
Generated on Sun May 8 2011 19:11:07 for Equalizer 1.0 by  doxygen 1.7.3