omnithread.h
上传用户:sbftbdw
上传日期:2007-01-03
资源大小:379k
文件大小:15k
源码类别:

远程控制编程

开发平台:

Visual C++

  1. // Package : omnithread
  2. // omnithread.h Created : 7/94 tjr
  3. //
  4. //    Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
  5. //
  6. //    This file is part of the omnithread library
  7. //
  8. //    The omnithread library is free software; you can redistribute it and/or
  9. //    modify it under the terms of the GNU Library General Public
  10. //    License as published by the Free Software Foundation; either
  11. //    version 2 of the License, or (at your option) any later version.
  12. //
  13. //    This library is distributed in the hope that it will be useful,
  14. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. //    Library General Public License for more details.
  17. //
  18. //    You should have received a copy of the GNU Library General Public
  19. //    License along with this library; if not, write to the Free
  20. //    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
  21. //    02111-1307, USA
  22. //
  23. //
  24. // Interface to OMNI thread abstraction.
  25. //
  26. // This file declares classes for threads and synchronisation objects
  27. // (mutexes, condition variables and counting semaphores).
  28. //
  29. // Wherever a seemingly arbitrary choice has had to be made as to the interface
  30. // provided, the intention here has been to be as POSIX-like as possible.  This
  31. // is why there is no semaphore timed wait, for example.
  32. //
  33. #ifndef __omnithread_h_
  34. #define __omnithread_h_
  35. #ifndef NULL
  36. #define NULL (void*)0
  37. #endif
  38. class omni_mutex;
  39. class omni_condition;
  40. class omni_semaphore;
  41. class omni_thread;
  42. //
  43. // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
  44. // implementation class - this may be useful for debugging.  Hopefully this
  45. // won't change the underlying structure which the compiler generates so that
  46. // this can work without recompiling the library.
  47. //
  48. #ifndef OMNI_THREAD_EXPOSE
  49. #define OMNI_THREAD_EXPOSE private
  50. #endif
  51. //
  52. // Include implementation-specific header file.
  53. //
  54. // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
  55. // condition variable, semaphore and thread.  Each should define any
  56. // implementation-specific members of the corresponding classes.
  57. //
  58. #if defined(__arm__) && defined(__atmos__)
  59. #include <omnithread/posix.h>
  60. #elif defined(__alpha__) && defined(__osf1__)
  61. #include <omnithread/posix.h>
  62. #elif defined(__powerpc__) && defined(__aix__)
  63. #include <omnithread/posix.h>
  64. #elif defined(__hpux__)
  65. #include <omnithread/posix.h>
  66. #elif defined(__WIN32__)
  67. #include <omnithread/nt.h>
  68. #ifdef _MSC_VER
  69. // Using MSVC++ to compile. If compiling library as a DLL,
  70. // define _OMNITHREAD_DLL. If compiling as a statuc library, define
  71. // _WINSTATIC
  72. // If compiling an application that is to be statically linked to omnithread,
  73. // define _WINSTATIC (if the application is  to be dynamically linked, 
  74. // there is no need to define any of these macros).
  75. #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
  76. #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
  77. #elif defined(_OMNITHREAD_DLL)
  78. #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
  79. #elif !defined(_WINSTATIC)
  80. #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
  81. #elif defined(_WINSTATIC)
  82. #define _OMNITHREAD_NTDLL_
  83. #endif
  84.  // _OMNITHREAD_DLL && _WINSTATIC
  85. #else
  86. // Not using MSVC++ to compile
  87. #define _OMNITHREAD_NTDLL_
  88. #endif
  89.  // _MSC_VER
  90.  
  91. #elif defined(__sunos__) && (__OSVERSION__ == 5)
  92. #ifdef UsePthread
  93. #include <omnithread/posix.h>
  94. #else
  95. #include <omnithread/solaris.h>
  96. #endif
  97. #elif defined(__linux__)
  98. #include <omnithread/posix.h>
  99. #elif defined(__nextstep__)
  100. #include <omnithread/mach.h>
  101. #elif defined(__VMS)
  102. #include <omnithread/posix.h>
  103. #elif defined(__SINIX__)
  104. #include <omnithread/posix.h>
  105. #elif defined(__osr5__)
  106. #include <omnithread/posix.h>
  107. #elif defined(__irix__)
  108. #include <omnithread/posix.h>
  109. #else
  110. #error "No implementation header file"
  111. #endif
  112. #if !defined(__WIN32__)
  113. #define _OMNITHREAD_NTDLL_
  114. #endif
  115. #if (!defined(OMNI_MUTEX_IMPLEMENTATION) || 
  116.      !defined(OMNI_CONDITION_IMPLEMENTATION) || 
  117.      !defined(OMNI_SEMAPHORE_IMPLEMENTATION) || 
  118.      !defined(OMNI_THREAD_IMPLEMENTATION))
  119. #error "Implementation header file incomplete"
  120. #endif
  121. //
  122. // This exception is thrown in the event of a fatal error.
  123. //
  124. class _OMNITHREAD_NTDLL_ omni_thread_fatal {
  125. public:
  126.     int error;
  127.     omni_thread_fatal(int e = 0) : error(e) {}
  128. };
  129. //
  130. // This exception is thrown when an operation is invoked with invalid
  131. // arguments.
  132. //
  133. class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
  134. ///////////////////////////////////////////////////////////////////////////
  135. //
  136. // Mutex
  137. //
  138. ///////////////////////////////////////////////////////////////////////////
  139. class _OMNITHREAD_NTDLL_ omni_mutex {
  140. public:
  141.     omni_mutex(void);
  142.     ~omni_mutex(void);
  143.     void lock(void);
  144.     void unlock(void);
  145.     void acquire(void) { lock(); }
  146.     void release(void) { unlock(); }
  147. // the names lock and unlock are preferred over acquire and release
  148. // since we are attempting to be as POSIX-like as possible.
  149.     friend class omni_condition;
  150. private:
  151.     // dummy copy constructor and operator= to prevent copying
  152.     omni_mutex(const omni_mutex&);
  153.     omni_mutex& operator=(const omni_mutex&);
  154. OMNI_THREAD_EXPOSE:
  155.     OMNI_MUTEX_IMPLEMENTATION
  156. };
  157. //
  158. // As an alternative to:
  159. // {
  160. //   mutex.lock();
  161. //   .....
  162. //   mutex.unlock();
  163. // }
  164. //
  165. // you can use a single instance of the omni_mutex_lock class:
  166. //
  167. // {
  168. //   omni_mutex_lock l(mutex);
  169. //   ....
  170. // }
  171. //
  172. // This has the advantage that mutex.unlock() will be called automatically
  173. // when an exception is thrown.
  174. //
  175. class _OMNITHREAD_NTDLL_ omni_mutex_lock {
  176.     omni_mutex& mutex;
  177. public:
  178.     omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
  179.     ~omni_mutex_lock(void) { mutex.unlock(); }
  180. private:
  181.     // dummy copy constructor and operator= to prevent copying
  182.     omni_mutex_lock(const omni_mutex_lock&);
  183.     omni_mutex_lock& operator=(const omni_mutex_lock&);
  184. };
  185. ///////////////////////////////////////////////////////////////////////////
  186. //
  187. // Condition variable
  188. //
  189. ///////////////////////////////////////////////////////////////////////////
  190. class _OMNITHREAD_NTDLL_ omni_condition {
  191.     omni_mutex* mutex;
  192. public:
  193.     omni_condition(omni_mutex* m);
  194. // constructor must be given a pointer to an existing mutex. The
  195. // condition variable is then linked to the mutex, so that there is an
  196. // implicit unlock and lock around wait() and timed_wait().
  197.     ~omni_condition(void);
  198.     void wait(void);
  199. // wait for the condition variable to be signalled.  The mutex is
  200. // implicitly released before waiting and locked again after waking up.
  201. // If wait() is called by multiple threads, a signal may wake up more
  202. // than one thread.  See POSIX threads documentation for details.
  203.     int timedwait(unsigned long secs, unsigned long nanosecs = 0);
  204. // timedwait() is given an absolute time to wait until.  To wait for a
  205. // relative time from now, use omni_thread::get_time. See POSIX threads
  206. // documentation for why absolute times are better than relative.
  207. // Returns 1 (true) if successfully signalled, 0 (false) if time
  208. // expired.
  209.     void signal(void);
  210. // if one or more threads have called wait(), signal wakes up at least
  211. // one of them, possibly more.  See POSIX threads documentation for
  212. // details.
  213.     void broadcast(void);
  214. // broadcast is like signal but wakes all threads which have called
  215. // wait().
  216. private:
  217.     // dummy copy constructor and operator= to prevent copying
  218.     omni_condition(const omni_condition&);
  219.     omni_condition& operator=(const omni_condition&);
  220. OMNI_THREAD_EXPOSE:
  221.     OMNI_CONDITION_IMPLEMENTATION
  222. };
  223. ///////////////////////////////////////////////////////////////////////////
  224. //
  225. // Counting semaphore
  226. //
  227. ///////////////////////////////////////////////////////////////////////////
  228. class _OMNITHREAD_NTDLL_ omni_semaphore {
  229. public:
  230.     omni_semaphore(unsigned int initial = 1);
  231.     ~omni_semaphore(void);
  232.     void wait(void);
  233. // if semaphore value is > 0 then decrement it and carry on. If it's
  234. // already 0 then block.
  235.     int trywait(void);
  236. // if semaphore value is > 0 then decrement it and return 1 (true).
  237. // If it's already 0 then return 0 (false).
  238.     void post(void);
  239. // if any threads are blocked in wait(), wake one of them up. Otherwise
  240. // increment the value of the semaphore.
  241. private:
  242.     // dummy copy constructor and operator= to prevent copying
  243.     omni_semaphore(const omni_semaphore&);
  244.     omni_semaphore& operator=(const omni_semaphore&);
  245. OMNI_THREAD_EXPOSE:
  246.     OMNI_SEMAPHORE_IMPLEMENTATION
  247. };
  248. //
  249. // A helper class for semaphores, similar to omni_mutex_lock above.
  250. //
  251. class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
  252.     omni_semaphore& sem;
  253. public:
  254.     omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
  255.     ~omni_semaphore_lock(void) { sem.post(); }
  256. private:
  257.     // dummy copy constructor and operator= to prevent copying
  258.     omni_semaphore_lock(const omni_semaphore_lock&);
  259.     omni_semaphore_lock& operator=(const omni_semaphore_lock&);
  260. };
  261. ///////////////////////////////////////////////////////////////////////////
  262. //
  263. // Thread
  264. //
  265. ///////////////////////////////////////////////////////////////////////////
  266. class _OMNITHREAD_NTDLL_ omni_thread {
  267. public:
  268.     enum priority_t {
  269. PRIORITY_LOW,
  270. PRIORITY_NORMAL,
  271. PRIORITY_HIGH
  272.     };
  273.     enum state_t {
  274. STATE_NEW, // thread object exists but thread hasn't
  275. // started yet.
  276. STATE_RUNNING, // thread is running.
  277. STATE_TERMINATED // thread has terminated but storage has not
  278. // been reclaimed (i.e. waiting to be joined).
  279.     };
  280.     //
  281.     // Constructors set up the thread object but the thread won't start until
  282.     // start() is called. The create method can be used to construct and start
  283.     // a thread in a single call.
  284.     //
  285.     omni_thread(void (*fn)(void*), void* arg = NULL,
  286. priority_t pri = PRIORITY_NORMAL);
  287.     omni_thread(void* (*fn)(void*), void* arg = NULL,
  288. priority_t pri = PRIORITY_NORMAL);
  289. // these constructors create a thread which will run the given function
  290. // when start() is called.  The thread will be detached if given a
  291. // function with void return type, undetached if given a function
  292. // returning void*. If a thread is detached, storage for the thread is
  293. // reclaimed automatically on termination. Only an undetached thread
  294. // can be joined.
  295.     void start(void);
  296. // start() causes a thread created with one of the constructors to
  297. // start executing the appropriate function.
  298. protected:
  299.     omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
  300. // this constructor is used in a derived class.  The thread will
  301. // execute the run() or run_undetached() member functions depending on
  302. // whether start() or start_undetached() is called respectively.
  303.     void start_undetached(void);
  304. // can be used with the above constructor in a derived class to cause
  305. // the thread to be undetached.  In this case the thread executes the
  306. // run_undetached member function.
  307.     virtual ~omni_thread(void);
  308. // destructor cannot be called by user (except via a derived class).
  309. // Use exit() or cancel() instead. This also means a thread object must
  310. // be allocated with new - it cannot be statically or automatically
  311. // allocated. The destructor of a class that inherits from omni_thread
  312. // shouldn't be public either (otherwise the thread object can be
  313. // destroyed while the underlying thread is still running).
  314. public:
  315.     void join(void**);
  316. // join causes the calling thread to wait for another's completion,
  317. // putting the return value in the variable of type void* whose address
  318. // is given (unless passed a null pointer). Only undetached threads
  319. // may be joined. Storage for the thread will be reclaimed.
  320.     void set_priority(priority_t);
  321. // set the priority of the thread.
  322.     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
  323.        priority_t pri = PRIORITY_NORMAL);
  324.     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
  325.        priority_t pri = PRIORITY_NORMAL);
  326. // create spawns a new thread executing the given function with the
  327. // given argument at the given priority. Returns a pointer to the
  328. // thread object. It simply constructs a new thread object then calls
  329. // start.
  330.     static void exit(void* return_value = NULL);
  331. // causes the calling thread to terminate.
  332.     static omni_thread* self(void);
  333. // returns the calling thread's omni_thread object.
  334. // If the calling thread is not the main thread and
  335. // is not created using this library, returns 0.
  336.     static void yield(void);
  337. // allows another thread to run.
  338.     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
  339. // sleeps for the given time.
  340.     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
  341.  unsigned long rel_sec = 0, unsigned long rel_nsec=0);
  342. // calculates an absolute time in seconds and nanoseconds, suitable for
  343. // use in timed_waits on condition variables, which is the current time
  344. // plus the given relative offset.
  345. private:
  346.     virtual void run(void* arg) {}
  347.     virtual void* run_undetached(void* arg) { return NULL; }
  348. // can be overridden in a derived class.  When constructed using the
  349. // the constructor omni_thread(void*, priority_t), these functions are
  350. // called by start() and start_undetached() respectively.
  351.     void common_constructor(void* arg, priority_t pri, int det);
  352. // implements the common parts of the constructors.
  353.     omni_mutex mutex;
  354. // used to protect any members which can change after construction,
  355. // i.e. the following 2 members:
  356.     state_t _state;
  357.     priority_t _priority;
  358.     static omni_mutex* next_id_mutex;
  359.     static int next_id;
  360.     int _id;
  361.     void (*fn_void)(void*);
  362.     void* (*fn_ret)(void*);
  363.     void* thread_arg;
  364.     int detached;
  365. public:
  366.     priority_t priority(void) {
  367. // return this thread's priority.
  368. omni_mutex_lock l(mutex);
  369. return _priority;
  370.     }
  371.     state_t state(void) {
  372. // return thread state (invalid, new, running or terminated).
  373. omni_mutex_lock l(mutex);
  374. return _state;
  375.     }
  376.     int id(void) { return _id; }
  377. // return unique thread id within the current process.
  378.     // This class plus the instance of it declared below allows us to execute
  379.     // some initialisation code before main() is called.
  380.     class _OMNITHREAD_NTDLL_ init_t {
  381. static int count;
  382.     public:
  383. init_t(void);
  384.     };
  385.     friend class init_t;
  386. OMNI_THREAD_EXPOSE:
  387.     OMNI_THREAD_IMPLEMENTATION
  388. };
  389. static omni_thread::init_t omni_thread_init;
  390. #endif