00001 // $Id: thread.h,v 1.15 2006/06/24 09:39:28 dvermeir Exp $ 00002 #ifndef DV_THREAD_THREAD_H 00003 #define DV_THREAD_THREAD_H 00004 00005 #include <setjmp.h> 00006 #include <dvthread/monitor.h> 00007 #include <iostream> 00008 00009 /** 00010 * @mainpage 00011 * 00012 * @author dvermeir@vub.ac.be 00013 * 00014 * <a href="../download/">Download</a> 00015 * 00016 * @section Installation Installation 00017 * 00018 * Standard. See the INSTALL file in the top directory. 00019 * 00020 * @section Description Description 00021 * This package provides two main classes: Dv::Thread::Thread, 00022 * representing threads, and Dv::Thread::Monitor, to represent 00023 * monitors. In addition, there is a trivial convenience class 00024 * Dv::Thread::Lock that can be used to conveniently ensure 00025 * exclusive access for member functions to *this (where *this 00026 * is an instance of (a subclass of) Dv::Thread::Monitor. 00027 * 00028 * @section Example Example program 00029 * 00030 * The following class implements a buffer for concurrent access. 00031 * Note the use of the SYNCHRONIZED macro which ensures that the get() 00032 * and put() member functions have exclusive access to the Buffer 00033 * object. Conditions are used to signal threads waiting to put or get 00034 * items into (from) the buffer. 00035 * @include buffer.h 00036 * 00037 * The example below shows the implementation of a reader thread class 00038 * for the above buffer. 00039 * Each thread should implement a Thread::main() member function 00040 * that describes the work to be done by the thread. 00041 * @include reader.h 00042 * 00043 * This example shows the implementation of a writer thread class. 00044 * Each thread should implement a Thread::main() member function 00045 * that describes the work to be done by the thread. 00046 * @include writer.h 00047 * 00048 * The main program creates a Buffer object, a Reader and 00049 * a Writer thread. Note that the writer wants to put more items 00050 * than will be read. Consequently, it will throw an exception (from 00051 * within Buffer::put()). 00052 * @include test-thread.C 00053 */ 00054 namespace Dv { 00055 namespace Thread { 00056 /** 00057 * Posix thread class. 00058 * 00059 * Example Thread class definitions: 00060 * <ul> 00061 * <li> A concurrent Buffer reader class. 00062 * \include reader.h 00063 * <li> A concurrent Buffer writer class. 00064 * \include writer.h 00065 * </ul> 00066 * \see Dv::Thread::Monitor 00067 */ 00068 class Thread { 00069 public: 00070 enum errors { 00071 BAD_EXCEPTION = -1 /** status of thread that threw a non-int exception */, 00072 DEFAULT_MAIN = -2 /** status of thread run with default main() */ 00073 }; 00074 00075 /** Constructor. 00076 * @param delete_after_main if true, \a delete(t) will 00077 * be executed after \a t->main() has completed. 00078 * @sa Dv::Thread::Thread::delete_after_main 00079 */ 00080 Thread(bool delete_after_main = false) throw (std::runtime_error); 00081 00082 /** Destructor. */ 00083 virtual ~Thread(); 00084 /** Start up thread. This function will execute main(). 00085 * @return 0 iff ok, system errno else. 00086 * @exception runtime_error if thread is already running. 00087 */ 00088 int start() throw (std::runtime_error); 00089 00090 /** Main function of thread. 00091 * @return the value to keep in set_status 00092 * Note that this function should not throw any exceptions 00093 * except integers. 00094 * The library will catch any exception e that is thrown erroneously, 00095 * print e.what() on cerr and return an exit status of BAD_EXCEPTION. 00096 * @sa Dv::Thread::Thread::start 00097 * @sa Dv::Thread::Thread::BAD_EXCEPTION 00098 * @sa Dv::Thread::Thread::exit 00099 * @sa Dv::Thread::Thread::set_status 00100 */ 00101 virtual int main(); 00102 00103 /** This function is called by the thread as a response to a SIGFPE signal being 00104 * delivered from another thread, using Thread::kill. This function 00105 * is then called the internal handler for this signal. 00106 * @warning This function should not throw any exceptions or chaos will 00107 * result. Typical usage might be: 00108 * @code 00109 * class MyThread { 00110 * public: 00111 * ... 00112 * void main() throw() { 00113 * while (!killed_ && socket_>>line) { 00114 * ... 00115 * } 00116 * } 00117 * void killed() throw () { 00118 * killed_ = true; 00119 * socket_.close(); 00120 * } 00121 * } 00122 * @endcode 00123 */ 00124 virtual void killed() throw () { return; } 00125 /** Wait for this thread to finish. 00126 * @return 0 iff ok, see manpage for @a pthread_self for other 00127 * possibities. 00128 * @warning only works for non-detached threads. 00129 * @sa Dv::Thread::Thread::detach 00130 * @code 00131 * MyThread t; 00132 * cout << "starting t" << endl; 00133 * t.start(); 00134 * cout << "waiting for t to finish" << endl; 00135 * t.join(); 00136 * @endcode 00137 */ 00138 int join() const throw (); 00139 00140 /** Kill a thread. This function delivers a <code>SIGFPE</code> signal to the 00141 * thread using <code>pthread_kill(id_,SIGFPE1)</code>. The signal is caught 00142 * and handled internally by calling Dv::Thread::Thread::killed(). 00143 * @exception runtime_error for a thread that tries to kill itself. 00144 * @sa Dv::Thread::Thread::killed 00145 */ 00146 int kill() const throw (std::runtime_error); 00147 /** Return exit status of this thread. 00148 * @return exit status of thread. 00149 */ 00150 int status() const { return exit_status_; } 00151 void set_status(int status) { exit_status_ = status; } 00152 00153 /** Return posix thread id of this thread. 00154 * @return Posix thread id. 00155 */ 00156 pthread_t id() const { return id_; } 00157 00158 /** String representation of thread id of this thread. 00159 * @return string representation of the id of this thread 00160 */ 00161 std::string sid() const; 00162 00163 /** Detach this thread. 00164 * Threads are created as ``joinable'', this function makes this 00165 * impossible. It also ensures that all resources are freed when the 00166 * thread exits. 00167 * @warning To avoid a memory leak, a thread must be joined or 00168 * detached. 00169 * @return *this 00170 * @sa Dv::Thread::Thread::join 00171 */ 00172 Thread& detach(); 00173 00174 /** Delete this thread object after Thread::main() has completed. 00175 * This feature is handy when there are an unknown number of threads 00176 * that are created using new and the only thing to do after a 00177 * thread has finished is to delete the Thread object. 00178 * 00179 * The code below shows a typical example. 00180 * @code 00181 * class MyThread: public Dv::Thread::Thread { 00182 * public: 00183 * MyThread* make(); // factory method to prohibit non-heap allocation. 00184 * void main(); 00185 * private: 00186 * MyThread(...): Dv::Thread::Thread(true), .. { detach(); .. } 00187 * }; 00188 * 00189 * while (accept) { 00190 * MyThread::make()->start(); // will delete itself automatically 00191 * } 00192 * @endcode 00193 * @param yes if true, the object will be deleted after Thread::main 00194 * has finished. 00195 * @return *this 00196 */ 00197 Thread& delete_after_main(bool yes) { delete_after_main_ = yes; return *this; } 00198 00199 /** Will this thread object be deleted after Thread::main() has completed? 00200 * @return true iff this object will be deleted after Thread::main() 00201 * finished. 00202 */ 00203 bool delete_after_main() { return delete_after_main_; } 00204 00205 /** Is this thread the currently running thread? 00206 * @return true iff this thread is the currently running thread 00207 * @return false otherwise 00208 */ 00209 bool is_self() const; 00210 00211 /** Is this thread running? 00212 * @return true iff this thread has been created using pthread_create 00213 * @return false otherwise 00214 */ 00215 bool running() const { return id_ != 0; } 00216 00217 /** Return pointer to currently running thread. 00218 * @return pointer to currently running thread, may be 0 00219 * if the thread was not made by this library. 00220 */ 00221 static Thread* self() throw (std::runtime_error); 00222 00223 /** Return id (pthread_t) of currently running thread. 00224 * This works for any thread; it is actually just call to 00225 * pthread_self. 00226 * @return id of currently running thread. 00227 */ 00228 static pthread_t self_id() throw () { return pthread_self(); } 00229 00230 /** Finish this thread, with status. 00231 * @warning This is implemented by throwing the status integer 00232 * as an exception. Hence is your code catches integers, 00233 * as in 00234 * @code 00235 * try { 00236 * exit(3); 00237 * } 00238 * catch (integer e) { 00239 * } 00240 * @endcode 00241 * the thread will not exit. 00242 * 00243 * The implementation of this function was changed between 00244 * versions 0.4 and 0.5 because the previous implementation, 00245 * which used @a pthread_exit, gave problems on systems with 00246 * the nptl thread implementation. 00247 * @param status to return. 00248 */ 00249 static void exit(int status); 00250 00251 /** Stream to log info on, if not 0. */ 00252 static std::ostream* log; 00253 00254 protected: 00255 /** This function is called by the thread as a response to a SIGFPE signal being 00256 * delivered from another thread, using Dv::Thread::Thread::signal. The signal handler 00257 * is internal. 00258 * Typical usage might be: 00259 * @code 00260 * class MyThread { 00261 * public: 00262 * ... 00263 * void main() throw() { 00264 * while (!killed_ && socket_>>line) { 00265 * ... 00266 * } 00267 * void killed() { 00268 * killed_ = true; 00269 * socket_.close(); 00270 * } 00271 * } 00272 * @endcode 00273 * @warning This function should not throw any exceptions or chaos will 00274 * result, because exception throwing from signal handlers is 00275 * currently not supported for some cpu types. 00276 */ 00277 private: 00278 /** Posix thread id. */ 00279 pthread_t id_; 00280 /** Posix thread attributes. */ 00281 pthread_attr_t attributes_; 00282 /** Exit status of this thread. */ 00283 int exit_status_; 00284 /** Forbid cctor. */ 00285 Thread(const Thread&); 00286 /** Forbid assignment. */ 00287 Thread& operator=(const Thread&); 00288 /** Should this object be deleted after Thread::main has completed? */ 00289 bool delete_after_main_; 00290 /** Is a signal handler for SIGFPE installed? This should really 00291 * be private but it is not since it is set from a C function */ 00292 bool signal_handler_installed; 00293 public: 00294 /** Set signal_handler_installed. This function does nothing if 00295 * not called by the thread itself. 00296 * @sa Dv::Thread::Thread::is_self 00297 */ 00298 void set_signal_handler_installed(); 00299 }; 00300 } 00301 } 00302 #endif
dvthread-0.5.0 | [22 June, 2006] |