#ifndef __ThreadClass_h_ #define __ThreadClass_h_ #include ///////////////////////////////////////////////////////////////////// // ThreadClass // // This provides some of the commonly used support for people who use // threads. A user will typically: // 1) Create a new class and privately inherit from this class. // 2) Implement threadFunction(). This is what is called in the new thread. // The thread will exit when this function returns. // 3) Optionally call startThread from the constructor. // 4) In the destructor, send a request asking the thread to stop, then // call waitForThread() to make sure the object is not destroyed before // the thread is finished with it. // // You don't have to start the thread. You can only start the thread once. // // If you need a destructor, do it the way it's described above. The // destructor for the base class will not be called until after the fields // of the derived class have been destroyed. You don't want that to happen // before the thread stops. // // However, more and more ThreadClass subclasses put assert(false) into // their destructors. Most threads were designed to run forever. Because // each thread is listening to other threads, it's hard to gracefully // shut down one thread. If you have subscribed to any data, you need a way // to unsubscribe, and a way to know that the producer thread has processed // the unsubscribe request. We've never implemented that. // // Long ago I was more concerned about shutting down threads. Originally // I had some code in main() that would return on certain errors, and that // would only work if the threads we'd already created could shut down. // Otherwise the program would hang forever. That's very bad since we normally // run in a loop, automatically restarting a program as soon as it dies. // // This is no longer an issue. Now we always exit with _exit() or with // abort(). These will not try to do any cleanup. // // Originally a lot of modules would start directly from ThreadClass. // This caused a lot of boilerplate code, and a lot of threads. It also // made things tough if you wanted reusable code that could listen to events // or go to sleep. Most of time you should consider starting from // ForeverThreadUser. ForeverThreadUser solves those exact problems. ///////////////////////////////////////////////////////////////////// class ThreadClass { private: const std::string _name; pthread_t _thread; bool _threadStarted; static void *threadAdapter(void *me); protected: void startThread(); void waitForThread(); virtual void threadFunction() =0; public: ThreadClass(std::string name); virtual ~ThreadClass(); std::string getName() const { return _name; } // This can return NULL. Every thread we create is based on ThreadClass, // but if you call this in the main thread you will get NULL. Also, some // 3rd party libraries will create threads by going directly to the operating // system, rather than using this class. static ThreadClass *findThread(); static bool anyThreadStarted(); }; #endif