Thread.cpp (6937B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 #pragma hdrstop 29 #include "precompiled.h" 30 31 /* 32 ================================================================================================ 33 Contains the vartious ThreadingClass implementations. 34 ================================================================================================ 35 */ 36 37 /* 38 ================================================================================================ 39 40 idSysThread 41 42 ================================================================================================ 43 */ 44 45 /* 46 ======================== 47 idSysThread::idSysThread 48 ======================== 49 */ 50 idSysThread::idSysThread() : 51 threadHandle( 0 ), 52 isWorker( false ), 53 isRunning( false ), 54 isTerminating( false ), 55 moreWorkToDo( false ), 56 signalWorkerDone( true ) { 57 } 58 59 /* 60 ======================== 61 idSysThread::~idSysThread 62 ======================== 63 */ 64 idSysThread::~idSysThread() { 65 StopThread( true ); 66 if ( threadHandle ) { 67 Sys_DestroyThread( threadHandle ); 68 } 69 } 70 71 /* 72 ======================== 73 idSysThread::StartThread 74 ======================== 75 */ 76 bool idSysThread::StartThread( const char * name_, core_t core, xthreadPriority priority, int stackSize ) { 77 if ( isRunning ) { 78 return false; 79 } 80 81 name = name_; 82 83 isTerminating = false; 84 85 if ( threadHandle ) { 86 Sys_DestroyThread( threadHandle ); 87 } 88 89 threadHandle = Sys_CreateThread( (xthread_t)ThreadProc, this, priority, name, core, stackSize, false ); 90 91 isRunning = true; 92 return true; 93 } 94 95 /* 96 ======================== 97 idSysThread::StartWorkerThread 98 ======================== 99 */ 100 bool idSysThread::StartWorkerThread( const char * name_, core_t core, xthreadPriority priority, int stackSize ) { 101 if ( isRunning ) { 102 return false; 103 } 104 105 isWorker = true; 106 107 bool result = StartThread( name_, core, priority, stackSize ); 108 109 signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE ); 110 111 return result; 112 } 113 114 /* 115 ======================== 116 idSysThread::StopThread 117 ======================== 118 */ 119 void idSysThread::StopThread( bool wait ) { 120 if ( !isRunning ) { 121 return; 122 } 123 if ( isWorker ) { 124 signalMutex.Lock(); 125 moreWorkToDo = true; 126 signalWorkerDone.Clear(); 127 isTerminating = true; 128 signalMoreWorkToDo.Raise(); 129 signalMutex.Unlock(); 130 } else { 131 isTerminating = true; 132 } 133 if ( wait ) { 134 WaitForThread(); 135 } 136 } 137 138 /* 139 ======================== 140 idSysThread::WaitForThread 141 ======================== 142 */ 143 void idSysThread::WaitForThread() { 144 if ( isWorker ) { 145 signalWorkerDone.Wait( idSysSignal::WAIT_INFINITE ); 146 } else if ( isRunning ) { 147 Sys_DestroyThread( threadHandle ); 148 threadHandle = 0; 149 } 150 } 151 152 /* 153 ======================== 154 idSysThread::SignalWork 155 ======================== 156 */ 157 void idSysThread::SignalWork() { 158 if ( isWorker ) { 159 signalMutex.Lock(); 160 moreWorkToDo = true; 161 signalWorkerDone.Clear(); 162 signalMoreWorkToDo.Raise(); 163 signalMutex.Unlock(); 164 } 165 } 166 167 /* 168 ======================== 169 idSysThread::IsWorkDone 170 ======================== 171 */ 172 bool idSysThread::IsWorkDone() { 173 if ( isWorker ) { 174 // a timeout of 0 will return immediately with true if signaled 175 if ( signalWorkerDone.Wait( 0 ) ) { 176 return true; 177 } 178 } 179 return false; 180 } 181 182 /* 183 ======================== 184 idSysThread::ThreadProc 185 ======================== 186 */ 187 int idSysThread::ThreadProc( idSysThread * thread ) { 188 int retVal = 0; 189 190 try { 191 if ( thread->isWorker ) { 192 for( ; ; ) { 193 thread->signalMutex.Lock(); 194 if ( thread->moreWorkToDo ) { 195 thread->moreWorkToDo = false; 196 thread->signalMoreWorkToDo.Clear(); 197 thread->signalMutex.Unlock(); 198 } else { 199 thread->signalWorkerDone.Raise(); 200 thread->signalMutex.Unlock(); 201 thread->signalMoreWorkToDo.Wait( idSysSignal::WAIT_INFINITE ); 202 continue; 203 } 204 205 if ( thread->isTerminating ) { 206 break; 207 } 208 209 retVal = thread->Run(); 210 } 211 thread->signalWorkerDone.Raise(); 212 } else { 213 retVal = thread->Run(); 214 } 215 } catch ( idException & ex ) { 216 idLib::Warning( "Fatal error in thread %s: %s", thread->GetName(), ex.GetError() ); 217 // We don't handle threads terminating unexpectedly very well, so just terminate the whole process 218 _exit( 0 ); 219 } 220 221 thread->isRunning = false; 222 223 return retVal; 224 } 225 226 /* 227 ======================== 228 idSysThread::Run 229 ======================== 230 */ 231 int idSysThread::Run() { 232 // The Run() is not pure virtual because on destruction of a derived class 233 // the virtual function pointer will be set to NULL before the idSysThread 234 // destructor actually stops the thread. 235 return 0; 236 } 237 238 /* 239 ================================================================================================ 240 241 test 242 243 ================================================================================================ 244 */ 245 246 /* 247 ================================================ 248 idMyThread test class. 249 ================================================ 250 */ 251 class idMyThread : public idSysThread { 252 public: 253 virtual int Run() { 254 // run threaded code here 255 return 0; 256 } 257 // specify thread data here 258 }; 259 260 /* 261 ======================== 262 TestThread 263 ======================== 264 */ 265 void TestThread() { 266 idMyThread thread; 267 thread.StartThread( "myThread", CORE_ANY ); 268 } 269 270 /* 271 ======================== 272 TestWorkers 273 ======================== 274 */ 275 void TestWorkers() { 276 idSysWorkerThreadGroup<idMyThread> workers( "myWorkers", 4 ); 277 for ( ; ; ) { 278 for ( int i = 0; i < workers.GetNumThreads(); i++ ) { 279 // workers.GetThread( i )-> // setup work for this thread 280 } 281 workers.SignalWorkAndWait(); 282 } 283 }