thread.h
Engine/source/platform/threads/thread.h
Classes:
Public Typedefs
void(*
ThreadRunFunction )(void *data)
Detailed Description
Public Typedefs
typedef void(* ThreadRunFunction )(void *data)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#ifndef _PLATFORM_THREADS_THREAD_H_ 25#define _PLATFORM_THREADS_THREAD_H_ 26 27#ifndef _TORQUE_TYPES_H_ 28 #include "platform/types.h" 29#endif 30#ifndef _TVECTOR_H_ 31 #include "core/util/tVector.h" 32#endif 33#ifndef _PLATFORM_THREADS_MUTEX_H_ 34 #include "platform/threads/mutex.h" 35#endif 36#ifndef _TSINGLETON_H_ 37 #include "core/util/tSingleton.h" 38#endif 39 40 41// Forward ref used by platform code 42class PlatformThreadData; 43 44 45// Typedefs 46typedef void (*ThreadRunFunction)(void *data); 47 48class Thread 49{ 50public: 51 typedef void Parent; 52 53protected: 54 PlatformThreadData* mData; 55 56 /// Used to signal threads need to stop. 57 /// Threads set this flag to false in start() 58 U32 shouldStop; 59 60 /// Set the name of this thread for identification in debuggers. 61 /// Maybe a NOP on platforms that do not support this. Always a NOP 62 /// in non-debug builds. 63 void _setName( const char* name ); 64 65public: 66 /// If set, the thread will delete itself once it has finished running. 67 bool autoDelete; 68 69 /// Create a thread. 70 /// @param func The starting function for the thread. 71 /// @param arg Data to be passed to func, when the thread starts. 72 /// @param start_thread Supported for compatibility. Must be false. Starting threads from 73 /// within the constructor is not allowed anymore as the run() method is virtual. 74 Thread(ThreadRunFunction func = 0, void *arg = 0, bool start_thread = false, bool autodelete = false); 75 76 /// Destroy a thread. 77 /// The thread MUST be allowed to exit before it is destroyed. 78 virtual ~Thread(); 79 80 /// Start a thread. 81 /// Sets shouldStop to false and calls run() in a new thread of execution. 82 void start( void* arg = 0 ); 83 84 /// Ask a thread to stop running. 85 void stop() 86 { 87 shouldStop = true; 88 } 89 90 /// Block until the thread stops running. 91 /// @note Don't use this in combination with auto-deletion as otherwise the thread will kill 92 /// itself while still executing the join() method on the waiting thread. 93 bool join(); 94 95 /// Threads may call checkForStop() periodically to check if they've been 96 /// asked to stop. As soon as checkForStop() returns true, the thread should 97 /// clean up and return. 98 bool checkForStop() 99 { 100 return shouldStop; 101 } 102 103 /// Run the Thread's entry point function. 104 /// Override this method in a subclass of Thread to create threaded code in 105 /// an object oriented way, and without passing a function ptr to Thread(). 106 /// Also, you can call this method directly to execute the thread's 107 /// code in a non-threaded way. 108 virtual void run(void *arg = 0); 109 110 /// Returns true if the thread is running. 111 bool isAlive(); 112 113 /// Returns the platform specific thread id for this thread. 114 U32 getId(); 115}; 116 117 118/// 119class ThreadManager 120{ 121 Vector<Thread*> threadPool; 122 Mutex poolLock; 123 124 struct MainThreadId 125 { 126 U32 mId; 127 MainThreadId() 128 { 129 mId = ThreadManager::getCurrentThreadId(); 130 } 131 U32 get() 132 { 133 // Okay, this is a bit soso. The main thread ID may get queried during 134 // global ctor phase before MainThreadId's ctor ran. Since global 135 // ctors will/should all run on the main thread, we can sort of safely 136 // assume here that we can just query the current thread's ID. 137 138 if( !mId ) 139 mId = ThreadManager::getCurrentThreadId(); 140 return mId; 141 } 142 }; 143 144 static MainThreadId smMainThreadId; 145 146public: 147 ThreadManager() 148 { 149 VECTOR_SET_ASSOCIATION( threadPool ); 150 } 151 152 /// Return true if the caller is running on the main thread. 153 static bool isMainThread(); 154 155 /// Returns true if threadId is the same as the calling thread's id. 156 static bool isCurrentThread(U32 threadId); 157 158 /// Returns true if the 2 thread ids represent the same thread. Some thread 159 /// APIs return an opaque object as a thread id, so the == operator cannot 160 /// reliably compare thread ids. 161 // this comparator is needed by pthreads and ThreadManager. 162 static bool compare(U32 threadId_1, U32 threadId_2); 163 164 /// Returns the platform specific thread id of the calling thread. Some 165 /// platforms do not guarantee that this ID stays the same over the life of 166 /// the thread, so use ThreadManager::compare() to compare thread ids. 167 static U32 getCurrentThreadId(); 168 169 /// Returns the platform specific thread id ot the main thread. 170 static U32 getMainThreadId() { return smMainThreadId.get(); } 171 172 /// Each thread should add itself to the thread pool the first time it runs. 173 static void addThread(Thread* thread) 174 { 175 ThreadManager &manager = *ManagedSingleton< ThreadManager >::instance(); 176 manager.poolLock.lock(); 177 Thread *alreadyAdded = getThreadById(thread->getId()); 178 if(!alreadyAdded) 179 manager.threadPool.push_back(thread); 180 manager.poolLock.unlock(); 181 } 182 183 static void removeThread(Thread* thread) 184 { 185 ThreadManager &manager = *ManagedSingleton< ThreadManager >::instance(); 186 manager.poolLock.lock(); 187 188 U32 threadID = thread->getId(); 189 for(U32 i = 0;i < manager.threadPool.size();++i) 190 { 191 if( compare( manager.threadPool[i]->getId(), threadID ) ) 192 { 193 manager.threadPool.erase(i); 194 break; 195 } 196 } 197 198 manager.poolLock.unlock(); 199 } 200 201 /// Searches the pool of known threads for a thread whose id is equivalent to 202 /// the given threadid. Compares thread ids with ThreadManager::compare(). 203 static Thread* getThreadById(U32 threadid) 204 { 205 AssertFatal(threadid != 0, "ThreadManager::getThreadById() Searching for a bad thread id."); 206 Thread* ret = NULL; 207 208 ThreadManager &manager = *ManagedSingleton< ThreadManager >::instance(); 209 manager.poolLock.lock(); 210 Vector<Thread*> &pool = manager.threadPool; 211 for( S32 i = pool.size() - 1; i >= 0; i--) 212 { 213 Thread* p = pool[i]; 214 if(compare(p->getId(), threadid)) 215 { 216 ret = p; 217 break; 218 } 219 } 220 manager.poolLock.unlock(); 221 return ret; 222 } 223 224 static Thread* getCurrentThread() 225 { 226 return getThreadById(ThreadManager::getCurrentThreadId()); 227 } 228 229 static const char* getSingletonName() 230 { 231 return "ThreadManager"; 232 } 233}; 234 235inline bool ThreadManager::isMainThread() 236{ 237 return compare( ThreadManager::getCurrentThreadId(), smMainThreadId.get() ); 238} 239 240inline bool ThreadManager::isCurrentThread(U32 threadId) 241{ 242 U32 current = getCurrentThreadId(); 243 return compare(current, threadId); 244} 245 246#endif // _PLATFORM_THREADS_THREAD_H_ 247