Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

threading.hpp 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. // threading.hpp
  2. //
  3. // (C) 2006 - 2009 MicroNeil Research Corporation.
  4. //
  5. // This program is part of the MicroNeil Research Open Library Project. For
  6. // more information go to http://www.microneil.com/OpenLibrary/index.html
  7. //
  8. // This program is free software; you can redistribute it and/or modify it
  9. // under the terms of the GNU General Public License as published by the
  10. // Free Software Foundation; either version 2 of the License, or (at your
  11. // option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful, but WITHOUT
  14. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. // more details.
  17. //
  18. // You should have received a copy of the GNU General Public License along with
  19. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. // Place, Suite 330, Boston, MA 02111-1307 USA
  21. // The "Threading" module is a basic, cross-platform, multi-threading tool kit.
  22. // The differences between posix compatible systems and win32 based systems are
  23. // abstracted. On win32 systems, native win32 primatives are used to construct.
  24. // efficient, lightweight objects.
  25. // On others we assume we can use pthreads. In either case the objects we have
  26. // here are designed to cover all of the basics efficiently while hiding the
  27. // required under-cover work.
  28. // A lot of this module is coded here in the header with the inline keyword
  29. // because it is likely that the more basic objects can be efficiently compiled
  30. // as inline abstractions to native calls. Really basic systems won't need
  31. // anything beyond what is in this file.
  32. // 20070202.1601 _M Further research has suggested that using a Semaphore in
  33. // WIN32 environments in place of a CRITICAL_SECTION may provide the best
  34. // performance and stability on all platforms. Specifically, SMP platforms may
  35. // race and waste resources with CRITICAL_SECTIONs and in those cases it is
  36. // recommended that the CRITICAL_SECTIONs may be "throttled" using Semaphores
  37. // to limit the number of threads that may contend for a critical section. It
  38. // is also suggested that if the Semaphore has an initialization value of 1
  39. // the CRITICAL_SECTION is redundant. So this code has been modified to do
  40. // precisely that!
  41. //
  42. // This new version also includes a ProductionGateway object that simplifies
  43. // the producer/consumer model. The object keeps track of the number of calls
  44. // to produce() and consume() and ensures that threads will block on consume()
  45. // until a sufficient number of calls to produce() are made. That is, for every
  46. // one call to produce(), a call to consume() will be allowed to proceed. The
  47. // object also allows for the potentially asynchronous nature of these calls.
  48. // 20070530.1751 _M Added top level exception handling in threads along with
  49. // isRunning() and isBad() methods.
  50. // 20060528.1647 _M All of the basics are complete and tested on both WIN32 and
  51. // RHEL4 single and multiple processors.
  52. // Include MNR_threading Once Only =============================================
  53. #ifndef MNR_threading
  54. #define MNR_threading
  55. #include <cassert>
  56. #include <set>
  57. #include <vector>
  58. #include <string>
  59. using namespace std;
  60. class ThreadManager; // ThreadManager does exist.
  61. extern ThreadManager Threads; // Master thread manager.
  62. ////////////////////////////////////////////////////////////////////////////////
  63. // Thread Status & Type
  64. //
  65. // ThreadState objects are constant static objects defined for each Thread class
  66. // so that the thread can update it's state by changing a pointer. The state
  67. // can then be compared between threads of the same type and can be read-out
  68. // as text for debugging purposes.
  69. class ThreadState { // Thread State Object.
  70. public:
  71. const string Name; // Text name of thread descriptor.
  72. ThreadState(string N) : Name(N) {} // Constructor requires text name.
  73. };
  74. // ThreadType objects are constant static objects defined for each Thread class
  75. // so that classes can be identified by type using a pointer to the constant.
  76. class ThreadType {
  77. public:
  78. const string Name;
  79. ThreadType(string N) : Name(N) {}
  80. };
  81. class Thread; // There is such thing as a Thread.
  82. class ThreadStatusRecord { // Describes a Thread's condition.
  83. private:
  84. Thread* Pointer; // A pointer to the thread.
  85. ThreadType* Type; // A descriptor of it's type.
  86. ThreadState* State; // A descriptor of it's state.
  87. string Name; // Name of the thread if any.
  88. bool isRunning; // True if the thread is running.
  89. bool isBad; // True if the thread is bad.
  90. string Fault; // Bad Thread's Fault if any.
  91. public:
  92. ThreadStatusRecord( // Initialize all items.
  93. Thread* P,
  94. ThreadType& T,
  95. ThreadState& S,
  96. bool R,
  97. bool B,
  98. string F,
  99. string N
  100. ) :
  101. Pointer(P),
  102. Type(&T),
  103. State(&S),
  104. isRunning(R),
  105. isBad(B),
  106. Fault(F),
  107. Name(N)
  108. {}
  109. ThreadStatusRecord& operator=(const ThreadStatusRecord& Right) { // Minimal Assignment Operator
  110. Pointer = Right.Pointer;
  111. Type = Right.Type;
  112. State = Right.State;
  113. isRunning = Right.isRunning;
  114. isBad = Right.isBad;
  115. Fault = Right.Fault;
  116. Name = Right.Name;
  117. }
  118. bool operator<(const ThreadStatusRecord& Right) { // Minimal Comparison Operator.
  119. return (Pointer < Right.Pointer);
  120. }
  121. // How to get the details of the report.
  122. const Thread* getPointer() { return Pointer; }
  123. const ThreadType& getType() { return *Type; }
  124. const ThreadState& getState() { return *State; }
  125. bool getRunning() { return isRunning; }
  126. bool getBad() { return isBad; }
  127. string getFault() { return Fault; }
  128. string getName() { return Name; }
  129. };
  130. typedef vector<ThreadStatusRecord> ThreadStatusReport; // Status report type.
  131. // End ThreadDescriptor
  132. ////////////////////////////////////////////////////////////////////////////////
  133. ////////////////////////////////////////////////////////////////////////////////
  134. // Win32 / POSIX abstractions
  135. #ifdef WIN32
  136. // When in WIN32 land...
  137. // Remember to compile (on GNU anyway) with -mthreads
  138. #include <windows.h>
  139. #include <process.h>
  140. typedef HANDLE thread_primative; // The WIN32 thread primative abstracts
  141. // HANDLE
  142. typedef HANDLE mutex_primative; // The WIN32 mutex primative abstracts
  143. // a HANDLE to a Semaphore.
  144. inline void threading_yield() { // When we want to yield time in WIN32
  145. SwitchToThread(); // we call SwitchToThread();
  146. }
  147. #else
  148. // When in POSIX land...
  149. // Remember to compile (on GMU anyway) with -pthread
  150. #include <pthread.h>
  151. #include <sched.h>
  152. typedef pthread_t thread_primative; // The POSIX thread primative abstracts
  153. // pthread_t
  154. typedef pthread_mutex_t mutex_primative; // The POSIX mutex primative abstracts
  155. // pthread_mutex_t
  156. inline void threading_yield() { // When we want to yield time in POSIX
  157. sched_yield(); // we call sched_yield();
  158. }
  159. #endif
  160. // End Win32 / POSIX abstractions
  161. ////////////////////////////////////////////////////////////////////////////////
  162. ////////////////////////////////////////////////////////////////////////////////
  163. // The Thread class gets extended to do any specific work. The pure virtual
  164. // function MyTask is overloaded by the derived class to define that work. It
  165. // is expected that the class will be initialized with any parameters that
  166. // will be used by the thread and that the thread will make available any
  167. // results through public interfaces either during and/or after the thread
  168. // has finished running.
  169. class Thread {
  170. private:
  171. ThreadState* MyThreadState; // Track current thread state.
  172. protected:
  173. const ThreadType& MyThreadType; // Identify thread type.
  174. const string MyThreadName; // Name string of this instance.
  175. thread_primative MyThread; // Abstracted thread.
  176. bool RunningFlag; // True when thread is in myTask()
  177. bool BadFlag; // True when myTask() throws!
  178. string BadWhat; // Bad exception what() if any.
  179. void CurrentThreadState(const ThreadState& TS); // Set thread state.
  180. public:
  181. Thread(); // Constructor (just in case)
  182. Thread(const ThreadType& T, string N); // Construct with specific Type/Name
  183. ~Thread(); // Destructor (just in case)
  184. void run(); // Method to launch this thread.
  185. void join(); // Method to Join this thread.
  186. void launchTask(); // Launch and watch myTask().
  187. virtual void myTask() = 0; // The actual task must be overloaded.
  188. thread_primative getMyThread(); // Inspect my thread primative.
  189. bool isRunning(); // Return the Running flag state.
  190. bool isBad(); // Return the Bad flag state.
  191. const string MyFault(); // Return exception Bad fault if any.
  192. const string MyName(); // The thread's name.
  193. const ThreadType& MyType(); // Thread type for this thread.
  194. const ThreadState& MyState(); // Returns the current thread state.
  195. const ThreadState& CurrentThreadState(); // Returns the current thread state.
  196. ThreadStatusRecord StatusReport(); // Return's the thread's status reprt.
  197. // Constants for Thread...
  198. const static ThreadType Type; // The thread's type.
  199. const static ThreadState ThreadInitialized; // Constructed successfully.
  200. const static ThreadState ThreadStarted; // Started.
  201. const static ThreadState ThreadFailed; // Failed by unhandled exception.
  202. const static ThreadState ThreadStopped; // Stopped normally.
  203. const static ThreadState ThreadDestroyed; // Safety value for destructed Threads.
  204. };
  205. // End Thread
  206. ////////////////////////////////////////////////////////////////////////////////
  207. ////////////////////////////////////////////////////////////////////////////////
  208. // The Mutex class abstracts a lightweight, very basic mutex object.
  209. // As with the Thread object, more ellaborate forms can be built up from
  210. // this basic mechanism. An important design constraint for this basic
  211. // mutex object is that it work even if the thread that's running was not
  212. // created with the Thread object... that ensures that it can be used in
  213. // code that is destined to function in other applications.
  214. class Mutex {
  215. private:
  216. mutex_primative MyMutex; // Here is our primative mutex.
  217. volatile bool IAmLocked; // Here is our Lock Count.
  218. public:
  219. Mutex(); // Construct the mutex.
  220. ~Mutex(); // Destroy the mutex.
  221. void lock(); // Lock it.
  222. void unlock(); // Unlock it.
  223. bool tryLock(); // Try to lock it.
  224. bool isLocked(); // Check to see if it's locked.
  225. };
  226. // End of Mutex
  227. ////////////////////////////////////////////////////////////////////////////////
  228. ////////////////////////////////////////////////////////////////////////////////
  229. // ScopeMutex
  230. // A ScopeMutex is a nifty trick for locking a mutex during some segment of
  231. // code. On construction, it locks the Mutex that it is given and keeps it
  232. // locked until it is destroyed. Of course this also means that it will unlock
  233. // the mutex when it goes out of scope - which is precisely the point :-)
  234. //
  235. // The right way to use a ScopeMutex is to create it just before you need to
  236. // have control and then forget about it. From a design perspective, you might
  237. // want to make sure that whatever happens after the ScopeMutex has been
  238. // created is as short as possible and if it is not then you may want to
  239. // use the Mutex directly.
  240. //
  241. // The best place to use a ScopeMutex is where you might leave the controling
  242. // bit of code through a number of logical paths such as a logic tree or even
  243. // due to some exceptions. In this context it saves you having to track down
  244. // all of the possible cases and unlock the mutex in each of them.
  245. class ScopeMutex {
  246. private:
  247. Mutex& MyMutex; // ScopeMutex has an ordinary Mutex to use.
  248. public:
  249. ScopeMutex(Mutex& M); // Constructing a ScopeMutex requires a Mutex
  250. ~ScopeMutex(); // We do have special code for descrution.
  251. };
  252. // End ScopeMutex
  253. ////////////////////////////////////////////////////////////////////////////////
  254. ////////////////////////////////////////////////////////////////////////////////
  255. // ProductionGateway
  256. // A ProductionGateway encapsulates the thread synchronization required for a
  257. // producer / consumer relationship. For each call to the produce() method one
  258. // call to the consume() method can proceed. The object takes into account that
  259. // these methods may be called out of sequence and that, for example, produce()
  260. // might be called several times before any calls to consume.
  261. #ifdef WIN32
  262. // Win32 Implementation ////////////////////////////////////////////////////////
  263. class ProductionGateway {
  264. private:
  265. HANDLE MySemaphore; // WIN32 makes this one easy w/ a 0 semi.
  266. public:
  267. ProductionGateway(); // The constructor and destructor handle
  268. ~ProductionGateway(); // creating and destroying the semi.
  269. void produce(); // Produce "releases" the semi.
  270. void consume(); // Consume "waits" if needed.
  271. };
  272. #else
  273. // POSIX Implementation ////////////////////////////////////////////////////////
  274. class ProductionGateway { // Posix needs a few pieces for this.
  275. private:
  276. mutex_primative MyMutex; // Mutex to protect the data.
  277. pthread_cond_t MyConditionVariable; // A condition variable for signaling.
  278. int Product; // A count of unused calls to produce()
  279. int Waiting; // A count of waiting threads.
  280. int Signaled; // A count of signaled threads.
  281. public:
  282. ProductionGateway(); // The constructor and destructor handle
  283. ~ProductionGateway(); // creating and destroying the semi.
  284. void produce(); // Produce "releases" the semi.
  285. void consume(); // Consume "waits" if needed.
  286. };
  287. #endif
  288. // End ProductionGateway
  289. ////////////////////////////////////////////////////////////////////////////////
  290. ////////////////////////////////////////////////////////////////////////////////
  291. // The ThreadManager class provides a global thread management tool. All Thread
  292. // objects register themselves with the Threads object upon construction and
  293. // remove themselves from the registry upon destruction. The Threads object can
  294. // produce a status report for all of the known threads on the system and can
  295. // temporarily lock the existing thread so that it can be contacted reliably.
  296. // locking and unlocking the ThreadManager is intended only for short messages
  297. // that set flags in the thread or pass some small data packet. The lock only
  298. // prevents the thread from being destroyed before the message can be sent so
  299. // that the thread that owns the threadlock will not make any calls to a dead
  300. // pointer. Most apps should be designed so that the threadlock mechanism is
  301. // not required.
  302. class ThreadManager { // Central manager for threads.
  303. friend class Thread; // Threads are friends.
  304. private:
  305. Mutex MyMutex; // Protect our data with this.
  306. set<Thread*> KnownThreads; // Keep track of all threads.
  307. void rememberThread(Thread* T); // Threads register themselves.
  308. void forgetThread(Thread* T); // Threads remove themselves.
  309. Thread* LockedThread; // Pointer to locked thread if any.
  310. public:
  311. ThreadManager():LockedThread(0){} // Initialize nice and clean.
  312. ThreadStatusReport StatusReport(); // Get a status report.
  313. bool lockExistingThread(Thread* T); // Locks ThreadManager if T exists.
  314. void unlockExistingThread(Thread* T); // Unlocks ThreadManager if T locked.
  315. };
  316. class ScopeThreadLock { // This is like a ScopeMutex for
  317. private: // the ThreadManager.
  318. Thread* MyLockedThread; // It needs to know it's Thread.
  319. public:
  320. ScopeThreadLock(Thread* T); // Locks T in ThreadManager if it can.
  321. ~ScopeThreadLock(); // Unlocks T in ThreadManager if locked.
  322. bool isGood(); // True if T was locked.
  323. bool isBad(); // False if T was not locked.
  324. };
  325. // End Thread Manager
  326. ////////////////////////////////////////////////////////////////////////////////
  327. #endif
  328. // End Of Include MNR_threading Once Only ======================================