library of assembled shared sources |
http://lass.cocamware.com |
00001 /** @file 00002 * @author Bram de Greve (bramz@users.sourceforge.net) 00003 * @author Tom De Muer (tomdemuer@users.sourceforge.net) 00004 * 00005 * *** BEGIN LICENSE INFORMATION *** 00006 * 00007 * The contents of this file are subject to the Common Public Attribution License 00008 * Version 1.0 (the "License"); you may not use this file except in compliance with 00009 * the License. You may obtain a copy of the License at 00010 * http://lass.sourceforge.net/cpal-license. The License is based on the 00011 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 00012 * use of software over a computer network and provide for limited attribution for 00013 * the Original Developer. In addition, Exhibit A has been modified to be consistent 00014 * with Exhibit B. 00015 * 00016 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 00017 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific 00018 * language governing rights and limitations under the License. 00019 * 00020 * The Original Code is LASS - Library of Assembled Shared Sources. 00021 * 00022 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer. 00023 * The Original Developer is the Initial Developer. 00024 * 00025 * All portions of the code written by the Initial Developer are: 00026 * Copyright (C) 2004-2007 the Initial Developer. 00027 * All Rights Reserved. 00028 * 00029 * Contributor(s): 00030 * 00031 * Alternatively, the contents of this file may be used under the terms of the 00032 * GNU General Public License Version 2 or later (the GPL), in which case the 00033 * provisions of GPL are applicable instead of those above. If you wish to allow use 00034 * of your version of this file only under the terms of the GPL and not to allow 00035 * others to use your version of this file under the CPAL, indicate your decision by 00036 * deleting the provisions above and replace them with the notice and other 00037 * provisions required by the GPL License. If you do not delete the provisions above, 00038 * a recipient may use your version of this file under either the CPAL or the GPL. 00039 * 00040 * *** END LICENSE INFORMATION *** 00041 */ 00042 00043 /** 00044 * @defgroup Threading Threading 00045 * Threading functions. The Mutex and Thread classes for WIN32 are almost literal copy and pastes 00046 * of the functions of wxWindows2.4.2. The implementation has changed a little bit to 00047 * use more of the LASS utility functions. The most noticible difference is in the thread 00048 * class where the Delete is not implemented, due to too large dependencies. The Critical 00049 * Section on WIN32 is an own implementation, just like all the UNIX Posix threading stuff. 00050 * 00051 * A little word on synchronization: in windows there are quite a few synchronisation 00052 * primitives and synchronized objects. Only the most common are implemented and wrapped 00053 * in the LASS environment: 00054 * Mutex : system-wide synchronisation object between processes/threads. Mutexes set in one process can be 00055 * unlocked in another one. That is the theory. In practice with the LASS 00056 * wrapping, there is no possibility to reference these mutexes in other 00057 * processes, named mutexes are not supported. Mutex are rather heavyweight 00058 * structures. Cannot be used for intrathread synchronisation AFAIK [TDM] 00059 * CriticalSection : process-wide synchronisation object between threads. Lightweight 00060 * construction. Cannot be used for intra-thread synchronisation. 00061 * Condition: this corresponds with MS Windows Events, can be used for interprocess/ 00062 * interthread and intrathread synchronisation. Not implemented in UNIX build. 00063 */ 00064 00065 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_THREAD_H 00066 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_THREAD_H 00067 00068 #include "util_common.h" 00069 #include "non_copyable.h" 00070 #include "atomic.h" 00071 00072 namespace lass 00073 { 00074 namespace util 00075 { 00076 namespace impl 00077 { 00078 class MutexInternal; 00079 class ConditionInternal; 00080 class ThreadInternal; 00081 class ThreadLocalStorageInternal; 00082 } 00083 00084 /** Return code for lock functions 00085 * @ingroup Threading 00086 * @see Mutex,CriticalSection 00087 */ 00088 enum LockResult 00089 { 00090 lockSuccess, /**< Mutex/CriticalSection is succesfully locked by this thread */ 00091 lockBusy /**< Mutex/CriticalSection is locked by another thread */ 00092 }; 00093 00094 /** Return code for wait functions 00095 * @ingroup Threading 00096 * @see Condition 00097 */ 00098 enum WaitResult 00099 { 00100 waitSuccess, /**< Wait is successfully terminated */ 00101 waitTimeout /**< Wait failed because of a timeout */ 00102 }; 00103 00104 /** ThreadKind. 00105 * @ingroup Threading 00106 * @see Thread 00107 */ 00108 enum ThreadKind 00109 { 00110 threadDetached, /**< detached thread */ 00111 threadJoinable /**< joinable thread, can be waited for */ 00112 }; 00113 00114 /** @ingroup Threading 00115 */ 00116 LASS_DLL extern unsigned numberOfProcessors; 00117 00118 /** Mutex. 00119 * @ingroup Threading 00120 * @see MutexLocker 00121 * A mutex is a systemwide synchronization object. It is heavier in use than a critical 00122 * section. For exception-safe basic use, the MutexLocker can be used. 00123 */ 00124 class LASS_DLL Mutex : NonCopyable 00125 { 00126 public: 00127 Mutex(); 00128 ~Mutex(); 00129 void lock(); 00130 const LockResult tryLock(); 00131 void unlock(); 00132 const bool isLocked() const; 00133 00134 private: 00135 impl::MutexInternal* pimpl_; 00136 }; 00137 00138 /** CriticalSection. 00139 * @ingroup Threading 00140 * @see CriticalSectionLocker 00141 * @author Tom De Muer [TDM] 00142 * @date 2004 00143 * Process wide synchronization object. The recommended object for interthread synchronisation 00144 * within a process in Windows. 00145 */ 00146 class LASS_DLL CriticalSection : NonCopyable 00147 { 00148 public: 00149 CriticalSection(); 00150 ~CriticalSection(); 00151 00152 void lock(); 00153 const LockResult tryLock(); 00154 void unlock(); 00155 00156 const bool isLocked() const; 00157 00158 private: 00159 void* pimpl_; 00160 }; 00161 00162 00163 00164 /** Condition. 00165 * @ingroup Threading 00166 * A condition can be used to synchronize using messages were a condition waits for 00167 * a signal or broadcast. A signal will only release one waiter, a broadcast will release 00168 * all current waiting wait-conditions. 00169 */ 00170 class LASS_DLL Condition: NonCopyable 00171 { 00172 public: 00173 Condition(); 00174 ~Condition(); 00175 void wait(); 00176 const WaitResult wait(unsigned long iMilliSeconds); 00177 void signal(); 00178 void broadcast(); 00179 private: 00180 impl::ConditionInternal* pimpl_; 00181 }; 00182 00183 /** A base class for threads. 00184 * @ingroup Threading 00185 * The virtual function doRun() needs to be overriden and after creation of the 00186 * thread on the heap or stack, the thread is in a state ready to be run. 00187 * The run() function actually starts the thread. 00188 * 00189 * JOINABLE threads can be waited for, DETACHED threads can not be waited for. 00190 */ 00191 class LASS_DLL Thread: NonCopyable 00192 { 00193 public: 00194 00195 enum 00196 { 00197 anyProcessor = unsigned(-1) /**< argument for Thread::bind to unbind the thread so it runs on any processor */ 00198 }; 00199 00200 virtual ~Thread(); 00201 00202 void run(); 00203 void join(); 00204 void bind(unsigned processor); 00205 00206 static void sleep(unsigned long milliseconds); 00207 static void yield(); 00208 static void bindCurrent(unsigned processor); 00209 00210 protected: 00211 00212 Thread(ThreadKind kind = threadDetached, const char* name = 0); 00213 00214 private: 00215 00216 friend class impl::ThreadInternal; 00217 00218 virtual void doRun() = 0; 00219 00220 impl::ThreadInternal* pimpl_; 00221 }; 00222 00223 00224 00225 /** A primitive to provide Thread Local Storage functionality 00226 * @ingroup Threading 00227 */ 00228 class LASS_DLL ThreadLocalStorage: NonCopyable 00229 { 00230 public: 00231 ThreadLocalStorage(void (*destructor)(void*) = 0); 00232 ~ThreadLocalStorage(); 00233 void* const get() const; 00234 void set(void* value); 00235 private: 00236 impl::ThreadLocalStorageInternal* pimpl_; 00237 }; 00238 00239 00240 00241 00242 /** A primitive to provide Thread Local Storage functionality for a first-citizen class. 00243 * @ingroup Threading 00244 * 00245 * @arg requirements: T must be copyconstructible. 00246 * 00247 * @warning 00248 * On Win32 platform, you should _access_ a ThreadLocalVariable inside code running 00249 * from a util::Thread (or util::threadFun for that matter). This is because the destructor 00250 * of the variable will _only_ be called on exit of a util::Thread. If you access it from 00251 * any other thread (even the main thread), the variable will correctly constructed for that 00252 * thread, but it will _never_ be destructed! 00253 * On a POSIX platform, this is not a problem though! The destructor will always be called. 00254 */ 00255 template <typename T> 00256 class ThreadLocalVariable: NonCopyable 00257 { 00258 public: 00259 typedef typename CallTraits<T>::TValue TValue; 00260 typedef typename CallTraits<T>::TParam TParam; 00261 typedef typename CallTraits<T>::TConstReference TConstReference; 00262 typedef typename CallTraits<T>::TReference TReference; 00263 00264 explicit ThreadLocalVariable(TParam prototype = T()): 00265 prototype_(prototype), 00266 storage_(&ThreadLocalVariable<T>::destructor) 00267 { 00268 } 00269 00270 TValue* const get() 00271 { 00272 TValue* ptr = static_cast<TValue*>(storage_.get()); 00273 if (!ptr) 00274 { 00275 std::auto_ptr<T> newCopy(new TValue(prototype_)); 00276 storage_.set(newCopy.get()); 00277 ptr = newCopy.release(); 00278 } 00279 return ptr; 00280 } 00281 00282 const TValue* const get() const 00283 { 00284 const TValue* ptr = static_cast<const TValue*>(storage_.get()); 00285 if (!ptr) 00286 { 00287 std::auto_ptr<T> newCopy(new TValue(prototype_)); 00288 storage_.set(newCopy.get()); 00289 ptr = newCopy.release(); 00290 } 00291 return ptr; 00292 } 00293 00294 TValue* const operator->() 00295 { 00296 return get(); 00297 } 00298 00299 const TValue* const operator->() const 00300 { 00301 return get(); 00302 } 00303 00304 TReference operator*() 00305 { 00306 return *get(); 00307 } 00308 00309 TConstReference operator*() const 00310 { 00311 return *get(); 00312 } 00313 00314 private: 00315 00316 static void destructor(void* p) 00317 { 00318 delete static_cast<T*>(p); 00319 } 00320 00321 TValue prototype_; 00322 mutable ThreadLocalStorage storage_; 00323 }; 00324 00325 00326 00327 /** Lean and mean synchronisation object, without OS support. 00328 * @ingroup Threading 00329 * @see SemaphoreLocker 00330 * @author Bram de Greve 00331 * @date 2004 00332 * 00333 * This semaphore is built upon atomic operations that are programmed in assembly. 00334 */ 00335 class LASS_DLL Semaphore : NonCopyable 00336 { 00337 public: 00338 Semaphore(int iNumberOfSlots = 1): 00339 freeSlots_(std::min(1, iNumberOfSlots)) 00340 { 00341 } 00342 00343 void lock() 00344 { 00345 int oldSlots, newSlots; 00346 do 00347 { 00348 oldSlots = freeSlots_; 00349 LASS_ASSERT(oldSlots >= 0); 00350 newSlots = oldSlots - 1; 00351 } 00352 while (oldSlots == 0 || !atomicCompareAndSwap(freeSlots_, oldSlots, newSlots)); 00353 } 00354 const LockResult tryLock() 00355 { 00356 int oldSlots, newSlots; 00357 do 00358 { 00359 oldSlots = freeSlots_; 00360 LASS_ASSERT(oldSlots >= 0); 00361 if (oldSlots == 0) 00362 { 00363 return lockBusy; 00364 } 00365 newSlots = oldSlots - 1; 00366 } 00367 while (!atomicCompareAndSwap(freeSlots_, oldSlots, newSlots)); 00368 return lockSuccess; 00369 } 00370 void unlock() 00371 { 00372 atomicIncrement(freeSlots_); 00373 } 00374 const bool isLocked() const 00375 { 00376 return freeSlots_ == 0; 00377 } 00378 00379 private: 00380 volatile int freeSlots_; 00381 }; 00382 00383 00384 00385 00386 00387 /** Common base class for lockers 00388 * @ingroup Threading 00389 */ 00390 class LockerBase 00391 { 00392 public: 00393 operator bool() const { return false; } 00394 }; 00395 00396 /** @ingroup Threading 00397 */ 00398 template <typename LockType> 00399 class Locker: public LockerBase 00400 { 00401 public: 00402 typedef LockType TLock; 00403 Locker(TLock& iLock): 00404 lock_(&iLock) 00405 { 00406 lock_->lock(); 00407 } 00408 ~Locker() 00409 { 00410 try 00411 { 00412 lock_->unlock(); 00413 } 00414 catch (std::exception& error) 00415 { 00416 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: " 00417 << "exception thrown in ~Locker(): " << error.what() << std::endl; 00418 } 00419 catch (...) 00420 { 00421 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: " 00422 << "unknown exception thrown in ~Locker()" << std::endl; 00423 } 00424 } 00425 TLock& mutex() 00426 { 00427 LASS_ASSERT(lock_); 00428 return *lock_; 00429 } 00430 void swap(Locker& iOther) 00431 { 00432 std::swap(lock_, iOther.lock_); 00433 } 00434 private: 00435 TLock* lock_; 00436 }; 00437 00438 /** @ingroup Threading 00439 * @relates Locker 00440 */ 00441 template <typename T> 00442 inline Locker<T> makeLocker(T& iLock) 00443 { 00444 return Locker<T>(iLock); 00445 } 00446 00447 /** typedef of Locker for Mutex 00448 * @ingroup Threading 00449 * @sa Mutex 00450 * @sa Locker 00451 */ 00452 typedef Locker<Mutex> MutexLocker; 00453 00454 /** typedef of Locker for CriticalSection 00455 * @ingroup Threading 00456 * @sa CriticalSection 00457 * @sa Locker 00458 */ 00459 typedef Locker<CriticalSection> CriticalSectionLocker; 00460 00461 /** typedef of Locker for Semaphore 00462 * @ingroup Threading 00463 * @sa Semaphore 00464 * @sa Locker 00465 */ 00466 typedef Locker<Semaphore> SemaphoreLocker; 00467 00468 } 00469 00470 } 00471 00472 /** @brief Locks a @a iLock and starts a scope block in which it remains locked. 00473 * @author [Bramz] 00474 * @ingroup Threading 00475 * 00476 * This macro starts a scope block through a @c if/else construct where the lock will be locked 00477 * on entering the scope, and will be unlocked on leaving the scope. You can use this scope in two 00478 * ways: by using the braces: 00479 * 00480 * @code 00481 * LASS_LOCK(lock) 00482 * { 00483 * // locked 00484 * doSomethingWhileLocked(); 00485 * } 00486 * // unlocked 00487 * @endcode 00488 * 00489 * Because the macro uses an @c if/else construct, you can ommit the braces if you only need one 00490 * statement in the locked scope: 00491 * 00492 * @code 00493 * LASS_LOCK(lock) doSomethingWhileLocked(); 00494 * @endcode 00495 * 00496 * @par requirements for @a iLock: 00497 * @a iLock can be of any type that implements two methods @c lock() and @c unlock(), that have 00498 * to do the obvious thing. Two excellent types to be used are lass::util::Mutex and 00499 * lass::util::CriticalSection. 00500 * 00501 * @par references: 00502 * <i>Concurrent Acces Control & C++</i>, C/C++ Users Journal, January 2004 00503 * 00504 * @note Guess what, for some reason bill gates might know, 00505 * @c LASS_UNIQUENAME(lassUtilImplGenericLocker) causes troubles in the @c win32_vc7_d build. 00506 * huray! Does the concatenation fails? It seems not, since in the preprocessor files 00507 * everything seems fine. And yet, it breaks. Hence, we had to give up on it, there's only 00508 * @c lassUtilImplGenericLocker now. I don't think that will cause any problems, since it's 00509 * inside an @c if/else scope block. But if you get name conflicts on LASS_LOCK, this might 00510 * be the reason ... 00511 */ 00512 #define LASS_LOCK(iLock)\ 00513 if (const ::lass::util::LockerBase& LASS_UNUSED(lassUtilImplLocker) =\ 00514 ::lass::util::makeLocker(iLock))\ 00515 {\ 00516 LASS_ASSERT_UNREACHABLE;\ 00517 }\ 00518 else 00519 00520 #endif
Generated on Mon Nov 10 14:21:40 2008 for Library of Assembled Shared Sources by 1.5.7.1 |