00001 /*************************************************************************** 00002 * * 00003 * (c) Art Tevs, MPI Informatik Saarbruecken * 00004 * mailto: <tevs@mpi-sb.mpg.de> * 00005 * * 00006 * This program is free software; you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation; either version 2 of the License, or * 00009 * (at your option) any later version. * 00010 * * 00011 ***************************************************************************/ 00012 00013 00014 #ifndef _NR_I_THREAD_H_ 00015 #define _NR_I_THREAD_H_ 00016 00017 //---------------------------------------------------------------------------------- 00018 // Includes 00019 //---------------------------------------------------------------------------------- 00020 #include "Prerequisities.h" 00021 00022 #include <boost/thread/thread.hpp> 00023 00024 namespace nrEngine{ 00025 00026 //! Abstract class to run a ITask in a thread controlled by Kernel 00027 /** 00028 * IThread is a base class for each kin dof tasks, allows also parallel 00029 * running of a task as a thread. Kernel tasks are derived from thi class 00030 * so a task has also a possibility to run in a own thread. Kernel 00031 * controls the creation and managing of threads. Threads communicate 00032 * through the engine's default communication protocol. 00033 * 00034 * Writing a task as a thread for your application is not a big issue. 00035 * You have to listen on kernel messages coming on the engine's default 00036 * channel to be able to react on stop/suspend/resume messages. Kernel 00037 * can not simply hold on a task. Because this can corrupt data if a task was 00038 * performing any important calculations. Also this is not a good style. 00039 * Kernel will provide a function to force a killing of a thread-task, but 00040 * prevent using of this function. 00041 * 00042 * Instead of killing the running threads, kernel will send a message about 00043 * stopping the thread. A thread-task should react on this event to 00044 * gracefully stop the execution. 00045 * 00046 * The thread interface does provide neccessary functions to your tasks, so 00047 * you do not have to think about managing the kernel messages by yourself. 00048 * Instead of this the thread will call taskStop() method to indicate the task, 00049 * that kernel want to stop the thread. Suspending the task will cause the kernel 00050 * to let the according thread sleeping until the task is resumed. There is 00051 * no other way how you can let the task sleep. 00052 * 00053 * So how the thread interface cooperate with the kernel and the task interface. 00054 * You write your task in the way, like if it were a simple task running 00055 * sequentially in the kernel. Each ITask itnerface is a derived class from 00056 * IThread but a thread portion of the code will only be active if you use the task 00057 * as a thread for the kernel. By marking the task as a thread i.e. by adding 00058 * the task to the kernel as a thread, you will activate the thread interface automatic. 00059 * Kernel will start the thread and will call the taskInit() and taskStart() functions 00060 * at the right moment. If the task is a thread, so it will call threadStart() instead 00061 * which will call thread_taskStart() method of derived ITask interface. The method 00062 * will call your taskStart() method, so you will not notice if there is a difference 00063 * between starting a task as a task or as a thread. 00064 * 00065 * In each cycle the kernel does call taskUpdate() method for sequential tasks. For 00066 * parallel tasks (threads) it does not call anything, because thread interface already 00067 * running and it will automaticaly call the appropritate taskUpdate() method, so 00068 * the task is getting updated. Also the thread base class does check if there is 00069 * any messages from the kernel (i.e. sleep or stop). If so it will call appropriate 00070 * methods in ITask interface. 00071 * 00072 * Our threads does yield their time slice to another threads after each execution cycle. 00073 * In this manner we get a friendly and intuitive behaviour of threads running in parallel. 00074 * 00075 * NOTE: The IThread interaface and Kernel does do all the job for you to manage 00076 * themself as a threads and to let them run in parallel. The only one thing it 00077 * can not manage for you is synchronisation. You have to worry about this by yourself 00078 * by using of mutex locking mechanism. 00079 * 00080 * \ingroup kernel 00081 **/ 00082 class _NRExport IThread{ 00083 public: 00084 /** 00085 * Virtual destructor so we are able to derive classes 00086 * with overloaded methods. 00087 **/ 00088 virtual ~IThread(); 00089 00090 protected: 00091 00092 /** 00093 * Protected constructor, so only the ITask-Interface 00094 * and friends are able to create an instance of this class. 00095 * In this way we protect wrong usage of this interface. 00096 **/ 00097 IThread(); 00098 00099 /** 00100 * Call this method if a thread goes into sleep mode. The derived 00101 * task should reimplement this method to call the appropriate suspend 00102 * method 00103 **/ 00104 virtual void _noticeSuspend() = 0; 00105 00106 /** 00107 * Call this method by waking up a thread. The derived task interface 00108 * should call the appropritate resume method 00109 **/ 00110 virtual void _noticeResume() = 0; 00111 00112 /** 00113 * Thread does call this method in a main loop. The method 00114 * should call the appropritate update method in ITask interface 00115 **/ 00116 virtual void _noticeUpdate() = 0; 00117 00118 /** 00119 * Call this method by stopping the execution of a thread. The underlying 00120 * task has to remove all used data, because after calling of this method 00121 * it will be destroyed 00122 **/ 00123 virtual void _noticeStop() = 0; 00124 00125 private: 00126 00127 /** 00128 * This is a entry point for a thread. The method is 00129 * static because it do not have to access any data 00130 * of the object itself. The given thread instance as a parameter 00131 * will be updated and managed as a thread. 00132 **/ 00133 static void run(void* mythread); 00134 00135 //! Kernel is a friend class 00136 friend class Kernel; 00137 00138 /** 00139 * Call the appropriate yield method of the threading library. 00140 * The thread calling this method will yield its remaining timeslice 00141 * to other threads. 00142 * 00143 * @param mythread Pointer to the thread which yields. 00144 * If NULL specified, so the called thread will be yield. 00145 **/ 00146 static void yield(IThread* mythread = NULL); 00147 00148 /** 00149 * Kernel does call this method if the appropriate task is running 00150 * as a thread in the kernel. This method manage the derived class by calling appropriate 00151 * virtual methods, which has to be reimplemented in the ITask interface. 00152 **/ 00153 void threadStart(); 00154 00155 /** 00156 * Kernel does call this method, if a thread should stop. 00157 **/ 00158 void threadStop(); 00159 00160 /** 00161 * Kernel call this method if a thread is going into sleep mode 00162 **/ 00163 void threadSuspend(); 00164 00165 /** 00166 * Kernel call this method if a thread is goind to resume 00167 **/ 00168 void threadResume(); 00169 00170 //! Define thread states 00171 enum ThreadState{ 00172 //! Thread is not running it is stopped 00173 THREAD_STOP, 00174 00175 //! Thread does running 00176 THREAD_RUNNING, 00177 00178 //! Thread is in sleep state (no action, but ready to wakeup) 00179 THREAD_SLEEPING, 00180 00181 //! Wakeup the thread as soon as possible 00182 THREAD_NEXT_RESUME, 00183 00184 //! Suspend the thread as soon as possible 00185 THREAD_NEXT_SUSPEND 00186 }; 00187 00188 //! This is a variable which will manage the thread state 00189 ThreadState mThreadState; 00190 00191 // Mutex to lock the data before use 00192 //pthread_mutex_t mMutex; 00193 00194 //! Store here the thread instance 00195 SharedPtr<boost::thread> mThread; 00196 00197 //! Thread attributes 00198 //pthread_attr_t mThreadAttr; 00199 00200 00201 //! Change a thread to new state, use mutex to lock the state 00202 void changeState(ThreadState newState); 00203 00204 }; 00205 00206 }; // end namespace 00207 #endif //_NR...