1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | /********************************************************************** * This is an example of using C++ classes within a C-style callback * framework, plus a rudimentary example of using POSIX threads. See < * http://www.fsmlabs.com/developers/docs/html/susv2/xsh/pthread.h.html * > for more information on POSIX threads in general. POSIX threads * are available on most Unix platforms, plus Windows via the Cygwin * package <http://www.cygwin.com/>. * * The Thread class defined here is hardly complete. It doesn't support * all thread operations that POSIX threads support; it doesn't even * support locking. For that reason, you should not use this code in * any sort of production environment. This is for educational purposes * only. * * If you're actually planning on working with threads, it would be * best to use a serious, portable, and supported threading library, * such as the following: * * * ACE * <http://www.cs.wustl.edu/~schmidt/ACE.html> * * Boost threads * <http://www.boost.org/libs/thread/doc/> * * GNU Common C++ * <http://www.gnu.org/software/commonc++/> * * Caveat haxor. * * P.S. Don't forget to link in the POSIX threads library. The * mechanism to do this varies from system to system. If you're using * g++, it may be as simple as this: * * g++ Thread.cpp main.cpp -pthread * * (On Cygwin, the -pthread flag elicits a warning, but still works.) * * There is also a makefile provided which will build the software for * you. If you have Make installed on your system, just run it: * * make * * If this doesn't work for you, consult your documentation. * **********************************************************************/ /********************************************************************** * Thread.hpp **********************************************************************/ #ifndef THREAD_HPP_eerniocgherioghv45ogin4h5g4 #define THREAD_HPP_eerniocgherioghv45ogin4h5g4 #include <pthread.h> //! Derive from this class to prevent copying or assignment in cases //! where such would be undesirable or ambiguous. //! See also <http://www.boost.org/libs/utility/utility.htm>. class Noncopyable { protected: Noncopyable () { } ~Noncopyable () { } private: Noncopyable (const Noncopyable &); // unimplemented Noncopyable &operator= (const Noncopyable &); // unimplemented }; //! Base class for an object which runs in its own thread of execution. class Thread : private Noncopyable { public: //! Start execution of the thread. //! @return 0 on success, or //! EAGAIN if thread could not be created due to system //! limitations or if the thread is already running. int start (); //! Determine whether this thread object is currently running. bool running () const; //! Waits for thread to finish. //! @return 0 on success, //! EINVAL if the thread could not be joined, //! ESRCH if the thread does not exist, or //! EDEADLK if joining this thread would cause deadlock. int join (); protected: Thread (); //! Waits for the thread to finish before destroying the Thread object. virtual ~Thread (); private: //! The ID of this thread object. //! Made volatile as per the recommendation of Alexei Alexandrescu //! in his article <http://www.cuj.com/experts/1902/alexandr.htm>. volatile pthread_t myId; //! Callback method supplied to pthread_create(). Return type void * //! is required by POSIX, but return value is ignored by this code. //! @param vthread pointer to a Thread object static void *do_start (void *vthread); //! Toggle whether this thread is running. void running (bool status); //! Called before run() in the new thread. virtual void init (); //! Called in the new thread. virtual void run (); //! Called after run() in the new thread. virtual void fini (); }; #endif /********************************************************************** * main.cpp **********************************************************************/ #include <iostream> #include <assert.h> #include <unistd.h> class MyThread : public Thread { private: virtual void init (); virtual void run (); virtual void fini (); }; int main (int argc, char *argv[]) { MyThread mythr; std::cout << "<main> starting" << std::endl; assert(!mythr.running()); assert(mythr.start() == 0); assert(mythr.running()); assert(mythr.join() == 0); assert(!mythr.running()); std::cout << "<main> done" << std::endl; return 0; } void MyThread::init () { std::cout << "<thread> MyThread::init()" << std::endl; } void MyThread::run () { std::cout << "<thread> begin MyThread::run()" << std::endl; for (int i = 0; i < 10; ++i) { std::cout << "<thread> " << i << std::endl; sleep(1); } std::cout << "<thread> end MyThread::run()" << std::endl; } void MyThread::fini () { std::cout << "<thread> MyThread::fini()" << std::endl; } /********************************************************************** * Thread.cpp **********************************************************************/ #include <errno.h> #include <unistd.h> namespace { const pthread_t notRunning = 0; } Thread::Thread () : myId(notRunning) { } int Thread::start () { return (!running() ? pthread_create(const_cast<pthread_t *>(&myId), 0, &do_start, this) : EAGAIN); } bool Thread::running () const { return (myId != notRunning); } void Thread::running (bool status) { // Note: pthread_create() also sets myId; however, Thread::init() might // be called before this occurs. Naturally, Thread::running() ought to // return true while the thread is running; hence, set myId here to make // sure of this. myId = status ? pthread_self() : notRunning; } int Thread::join () { return running() ? pthread_join(myId, 0) : ESRCH; } Thread::~Thread () { join(); } void *Thread::do_start (void *vthread) { Thread *thread = static_cast<Thread *>(vthread); thread->running(true); thread->init(); thread->run(); thread->fini(); thread->running(false); return 0; } void Thread::init () { } void Thread::run () { } void Thread::fini () { } |