ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GThreads.h
Revision: 156
Committed: Fri Jan 27 18:29:55 2012 UTC (7 years, 4 months ago) by gpertea
File size: 25477 byte(s)
Log Message:
adding refactored TinyThread++ code

Line File contents
1 /*
2 GThread - multi-platform thread support
3 this is heavily based on the source code of TinyThread++ 1.0 package by Marcus Geelnard
4 (with only minor modifications and namespace changes)
5
6 Original Copyright notice below
7 */
8
9 /*
10 Copyright (c) 2010 Marcus Geelnard
11
12 This software is provided 'as-is', without any express or implied
13 warranty. In no event will the authors be held liable for any damages
14 arising from the use of this software.
15
16 Permission is granted to anyone to use this software for any purpose,
17 including commercial applications, and to alter it and redistribute it
18 freely, subject to the following restrictions:
19
20 1. The origin of this software must not be misrepresented; you must not
21 claim that you wrote the original software. If you use this software
22 in a product, an acknowledgment in the product documentation would be
23 appreciated but is not required.
24
25 2. Altered source versions must be plainly marked as such, and must not be
26 misrepresented as being the original software.
27
28 3. This notice may not be removed or altered from any source
29 distribution.
30 */
31
32
33 #ifndef _GTHREADS_
34 #define _GTHREADS_
35
36 /// @file
37 /// @mainpage TinyThread++ API Reference
38 ///
39 /// @section intro_sec Introduction
40 /// TinyThread++ is a minimal, portable implementation of basic threading
41 /// classes for C++.
42 ///
43 /// They closely mimic the functionality and naming of the C++0x standard, and
44 /// should be easily replaceable with the corresponding std:: variants.
45 ///
46 /// @section port_sec Portability
47 /// The Win32 variant uses the native Win32 API for implementing the thread
48 /// classes, while for other systems, the POSIX threads API (pthread) is used.
49 ///
50 /// @section class_sec Classes
51 /// In order to mimic the threading API of the C++0x standard, subsets of
52 /// several classes are provided. The fundamental classes are:
53 /// @li GThread
54 /// @li GMutex
55 /// @li GRecursiveMutex
56 /// @li GConditionVariable
57 /// @li GLockGuard
58 ///
59 /// @section misc_sec Miscellaneous
60 /// The following special keywords are available: #thread_local.
61 ///
62 /// For more detailed information (including additional classes), browse the
63 /// different sections of this documentation. A good place to start is:
64 /// tinythread.h.
65
66 // Which platform are we on?
67 #if !defined(_GTHREADS_PLATFORM_DEFINED_)
68 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
69 #define _GTHREADS_WIN32_
70 #else
71 #define _GTHREADS_POSIX_
72 #endif
73 #define _GTHREADS_PLATFORM_DEFINED_
74 #endif
75
76 // Check if we can support the assembly language level implementation (otherwise
77 // revert to the system API)
78 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \
79 (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || \
80 (defined(__GNUC__) && (defined(__ppc__)))
81 #define _GFASTMUTEX_ASM_
82 #else
83 #define _FAST_MUTEX_SYS_
84 #endif
85
86 // Platform specific includes
87 #if defined(_GTHREADS_WIN32_)
88 #include <windows.h>
89 #else
90 #include <pthread.h>
91 #include <signal.h>
92 #include <sched.h>
93 #include <unistd.h>
94 #endif
95
96 // Generic includes
97 //#include <ostream>
98
99 /// TinyThread++ version (major number).
100 #define TINYTHREAD_VERSION_MAJOR 1
101 /// TinyThread++ version (minor number).
102 #define TINYTHREAD_VERSION_MINOR 0
103 /// TinyThread++ version (full version).
104 #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
105
106 // Do we have a fully featured C++0x compiler?
107 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
108 #define _GTHREADS_CPP0X_
109 #endif
110
111 // ...at least partial C++0x?
112 #if defined(_GTHREADS_CPP0X_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
113 #define _GTHREADS_CPP0X_PARTIAL_
114 #endif
115
116 // Macro for disabling assignments of objects.
117 #ifdef _GTHREADS_CPP0X_PARTIAL_
118 #define _GTHREADS_DISABLE_ASSIGNMENT(name) \
119 name(const name&) = delete; \
120 name& operator=(const name&) = delete;
121 #else
122 #define _GTHREADS_DISABLE_ASSIGNMENT(name) \
123 name(const name&); \
124 name& operator=(const name&);
125 #endif
126
127 /// @def thread_local
128 /// Thread local storage keyword.
129 /// A variable that is declared with the \c thread_local keyword makes the
130 /// value of the variable local to each thread (known as thread-local storage,
131 /// or TLS). Example usage:
132 /// @code
133 /// // This variable is local to each thread.
134 /// thread_local int variable;
135 /// @endcode
136 /// @note The \c thread_local keyword is a macro that maps to the corresponding
137 /// compiler directive (e.g. \c __declspec(thread)). While the C++0x standard
138 /// allows for non-trivial types (e.g. classes with constructors and
139 /// destructors) to be declared with the \c thread_local keyword, most pre-C++0x
140 /// compilers only allow for trivial types (e.g. \c int). So, to guarantee
141 /// portable code, only use trivial types for thread local storage.
142 /// @note This directive is currently not supported on Mac OS X (it will give
143 /// a compiler error), since compile-time TLS is not supported in the Mac OS X
144 /// executable format. Also, some older versions of MinGW (before GCC 4.x) do
145 /// not support this directive.
146 /// @hideinitializer
147
148 #if !defined(_GTHREADS_CPP0X_) && !defined(thread_local)
149 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
150 #define thread_local __thread
151 #else
152 #define thread_local __declspec(thread)
153 #endif
154 #endif
155
156 // HACK: Mac OS X and early MinGW do not support thread-local storage
157 #if defined(__APPLE__) || (defined(__MINGW32__) && (__GNUC__ < 4))
158 #define GTHREADS_NO_TLS
159 #endif
160
161
162 /// Main name space for TinyThread++.
163 /// This namespace is more or less equivalent to the \c std namespace for the
164 /// C++0x thread classes. For instance, the tthread::mutex class corresponds to
165 /// the std::mutex class.
166 //namespace tthread {
167
168 /// GMutex class
169 /// This is a mutual exclusion object for synchronizing access to shared
170 /// memory areas for several threads. The mutex is non-recursive (i.e. a
171 /// program may deadlock if the thread that owns a mutex object calls lock()
172 /// on that object).
173 /// @see recursive_mutex
174 class GMutex {
175 public:
176 /// Constructor.
177 GMutex()
178 #if defined(_GTHREADS_WIN32_)
179 : mAlreadyLocked(false)
180 #endif
181 {
182 #if defined(_GTHREADS_WIN32_)
183 InitializeCriticalSection(&mHandle);
184 #else
185 pthread_mutex_init(&mHandle, NULL);
186 #endif
187 }
188
189 /// Destructor.
190 ~GMutex()
191 {
192 #if defined(_GTHREADS_WIN32_)
193 DeleteCriticalSection(&mHandle);
194 #else
195 pthread_mutex_destroy(&mHandle);
196 #endif
197 }
198
199 /// Lock the mutex.
200 /// The method will block the calling thread until a lock on the mutex can
201 /// be obtained. The mutex remains locked until \c unlock() is called.
202 /// @see lock_guard
203 inline void lock()
204 {
205 #if defined(_GTHREADS_WIN32_)
206 EnterCriticalSection(&mHandle);
207 while(mAlreadyLocked) Sleep(1000); // Simulate deadlock...
208 mAlreadyLocked = true;
209 #else
210 pthread_mutex_lock(&mHandle);
211 #endif
212 }
213
214 /// Try to lock the mutex.
215 /// The method will try to lock the mutex. If it fails, the function will
216 /// return immediately (non-blocking).
217 /// @return \c true if the lock was acquired, or \c false if the lock could
218 /// not be acquired.
219 inline bool try_lock()
220 {
221 #if defined(_GTHREADS_WIN32_)
222 bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
223 if(ret && mAlreadyLocked)
224 {
225 LeaveCriticalSection(&mHandle);
226 ret = false;
227 }
228 return ret;
229 #else
230 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
231 #endif
232 }
233
234 /// Unlock the mutex.
235 /// If any threads are waiting for the lock on this mutex, one of them will
236 /// be unblocked.
237 inline void unlock()
238 {
239 #if defined(_GTHREADS_WIN32_)
240 mAlreadyLocked = false;
241 LeaveCriticalSection(&mHandle);
242 #else
243 pthread_mutex_unlock(&mHandle);
244 #endif
245 }
246
247 _GTHREADS_DISABLE_ASSIGNMENT(GMutex)
248
249 private:
250 #if defined(_GTHREADS_WIN32_)
251 CRITICAL_SECTION mHandle;
252 bool mAlreadyLocked;
253 #else
254 pthread_mutex_t mHandle;
255 #endif
256
257 friend class GConditionVar;
258 };
259
260 /// Recursive mutex class.
261 /// This is a mutual exclusion object for synchronizing access to shared
262 /// memory areas for several threads. The mutex is recursive (i.e. a thread
263 /// may lock the mutex several times, as long as it unlocks the mutex the same
264 /// number of times).
265 /// @see mutex
266 class GMutexRecursive {
267 public:
268 /// Constructor.
269 GMutexRecursive()
270 {
271 #if defined(_GTHREADS_WIN32_)
272 InitializeCriticalSection(&mHandle);
273 #else
274 pthread_mutexattr_t attr;
275 pthread_mutexattr_init(&attr);
276 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
277 pthread_mutex_init(&mHandle, &attr);
278 #endif
279 }
280
281 /// Destructor.
282 ~GMutexRecursive()
283 {
284 #if defined(_GTHREADS_WIN32_)
285 DeleteCriticalSection(&mHandle);
286 #else
287 pthread_mutex_destroy(&mHandle);
288 #endif
289 }
290
291 /// Lock the mutex.
292 /// The method will block the calling thread until a lock on the mutex can
293 /// be obtained. The mutex remains locked until \c unlock() is called.
294 /// @see lock_guard
295 inline void lock()
296 {
297 #if defined(_GTHREADS_WIN32_)
298 EnterCriticalSection(&mHandle);
299 #else
300 pthread_mutex_lock(&mHandle);
301 #endif
302 }
303
304 /// Try to lock the mutex.
305 /// The method will try to lock the mutex. If it fails, the function will
306 /// return immediately (non-blocking).
307 /// @return \c true if the lock was acquired, or \c false if the lock could
308 /// not be acquired.
309 inline bool try_lock()
310 {
311 #if defined(_GTHREADS_WIN32_)
312 return TryEnterCriticalSection(&mHandle) ? true : false;
313 #else
314 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
315 #endif
316 }
317
318 /// Unlock the mutex.
319 /// If any threads are waiting for the lock on this mutex, one of them will
320 /// be unblocked.
321 inline void unlock()
322 {
323 #if defined(_GTHREADS_WIN32_)
324 LeaveCriticalSection(&mHandle);
325 #else
326 pthread_mutex_unlock(&mHandle);
327 #endif
328 }
329
330 _GTHREADS_DISABLE_ASSIGNMENT(GMutexRecursive)
331
332 private:
333 #if defined(_GTHREADS_WIN32_)
334 CRITICAL_SECTION mHandle;
335 #else
336 pthread_mutex_t mHandle;
337 #endif
338
339 friend class GConditionVar;
340 };
341
342 /// Lock guard class.
343 /// The constructor locks the mutex, and the destructor unlocks the mutex, so
344 /// the mutex will automatically be unlocked when the lock guard goes out of
345 /// scope. Example usage:
346 /// @code
347 /// mutex m;
348 /// int counter;
349 ///
350 /// void increment()
351 /// {
352 /// lock_guard<mutex> guard(m);
353 /// ++ counter;
354 /// }
355 /// @endcode
356
357 template <class T>
358 class GLockGuard {
359 public:
360 typedef T mutex_type;
361
362 GLockGuard() : mMutex(0) {}
363
364 /// The constructor locks the mutex.
365 explicit GLockGuard(mutex_type &aMutex)
366 {
367 mMutex = &aMutex;
368 mMutex->lock();
369 }
370
371 /// The destructor unlocks the mutex.
372 ~GLockGuard()
373 {
374 if(mMutex)
375 mMutex->unlock();
376 }
377
378 private:
379 mutex_type * mMutex;
380 };
381
382 /// Condition variable class.
383 /// This is a signalling object for synchronizing the execution flow for
384 /// several threads. Example usage:
385 /// @code
386 /// // Shared data and associated mutex and condition variable objects
387 /// int count;
388 /// mutex m;
389 /// condition_variable cond;
390 ///
391 /// // Wait for the counter to reach a certain number
392 /// void wait_counter(int targetCount)
393 /// {
394 /// lock_guard<mutex> guard(m);
395 /// while(count < targetCount)
396 /// cond.wait(m);
397 /// }
398 ///
399 /// // Increment the counter, and notify waiting threads
400 /// void increment()
401 /// {
402 /// lock_guard<mutex> guard(m);
403 /// ++ count;
404 /// cond.notify_all();
405 /// }
406 /// @endcode
407 class GConditionVar {
408 public:
409 /// Constructor.
410 #if defined(_GTHREADS_WIN32_)
411 GConditionVar();
412 #else
413 GConditionVar()
414 {
415 pthread_cond_init(&mHandle, NULL);
416 }
417 #endif
418
419 /// Destructor.
420 #if defined(_GTHREADS_WIN32_)
421 ~GConditionVar();
422 #else
423 ~GConditionVar()
424 {
425 pthread_cond_destroy(&mHandle);
426 }
427 #endif
428
429 /// Wait for the condition.
430 /// The function will block the calling thread until the condition variable
431 /// is woken by \c notify_one(), \c notify_all() or a spurious wake up.
432 /// @param[in] aMutex A mutex that will be unlocked when the wait operation
433 /// starts, an locked again as soon as the wait operation is finished.
434 template <class _mutexT>
435 inline void wait(_mutexT &aMutex)
436 {
437 #if defined(_GTHREADS_WIN32_)
438 // Increment number of waiters
439 EnterCriticalSection(&mWaitersCountLock);
440 ++ mWaitersCount;
441 LeaveCriticalSection(&mWaitersCountLock);
442
443 // Release the mutex while waiting for the condition (will decrease
444 // the number of waiters when done)...
445 aMutex.unlock();
446 _wait();
447 aMutex.lock();
448 #else
449 pthread_cond_wait(&mHandle, &aMutex.mHandle);
450 #endif
451 }
452
453 /// Notify one thread that is waiting for the condition.
454 /// If at least one thread is blocked waiting for this condition variable,
455 /// one will be woken up.
456 /// @note Only threads that started waiting prior to this call will be
457 /// woken up.
458 #if defined(_GTHREADS_WIN32_)
459 void notify_one();
460 #else
461 inline void notify_one()
462 {
463 pthread_cond_signal(&mHandle);
464 }
465 #endif
466
467 /// Notify all threads that are waiting for the condition.
468 /// All threads that are blocked waiting for this condition variable will
469 /// be woken up.
470 /// @note Only threads that started waiting prior to this call will be
471 /// woken up.
472 #if defined(_GTHREADS_WIN32_)
473 void notify_all();
474 #else
475 inline void notify_all()
476 {
477 pthread_cond_broadcast(&mHandle);
478 }
479 #endif
480
481 _GTHREADS_DISABLE_ASSIGNMENT(GConditionVar)
482
483 private:
484 #if defined(_GTHREADS_WIN32_)
485 void _wait();
486 HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs.
487 unsigned int mWaitersCount; ///< Count of the number of waiters.
488 CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
489 #else
490 pthread_cond_t mHandle;
491 #endif
492 };
493
494
495 /// Thread class.
496 class GThread {
497 public:
498 #if defined(_GTHREADS_WIN32_)
499 typedef HANDLE native_handle_type;
500 #else
501 typedef pthread_t native_handle_type;
502 #endif
503
504 /// Default constructor.
505 /// Construct a \c thread object without an associated thread of execution
506 /// (i.e. non-joinable).
507 GThread() : mId(0), mHandle(0), mNotAThread(true)
508 #if defined(_GTHREADS_WIN32_)
509 , mWin32ThreadID(0)
510 #endif
511 {}
512
513 /// Thread starting constructor.
514 /// Construct a \c thread object with a new thread of execution.
515 /// @param[in] aFunction A function pointer to a function of type:
516 /// <tt>void fun(void * arg)</tt>
517 /// @param[in] aArg Argument to the thread function.
518 /// @note This constructor is not fully compatible with the standard C++
519 /// thread class. It is more similar to the pthread_create() (POSIX) and
520 /// CreateThread() (Windows) functions.
521 GThread(void (*aFunction)(void *, GThread*), void * aArg);
522
523 /// Destructor.
524 /// @note If the thread is joinable upon destruction, \c std::terminate()
525 /// will be called, which terminates the process. It is always wise to do
526 /// \c join() before deleting a thread object.
527 ~GThread();
528
529 /// Wait for the thread to finish (join execution flows).
530 void join();
531
532 /// Check if the thread is joinable.
533 /// A thread object is joinable if it has an associated thread of execution.
534 bool joinable() const;
535
536 /// Return the thread ID of a thread object.
537 int get_id() const; // { return mID; }
538
539 /// Get the native handle for this thread.
540 /// @note Under Windows, this is a \c HANDLE, and under POSIX systems, this
541 /// is a \c pthread_t.
542 inline native_handle_type native_handle()
543 {
544 return mHandle;
545 }
546
547 inline void yield() {
548 #if defined(_GTHREADS_WIN32_)
549 Sleep(0);
550 #else
551 sched_yield();
552 #endif
553 }
554 static int num_running() {
555 //return number of running (live) threads
556 static GMutex vLock;
557 GLockGuard<GMutex> guard(vLock);
558 int r=tcounter;
559 return r;
560 }
561 static int liveCount() {
562 //return number of running (live) threads
563 return num_running();
564 }
565 static void wait_all();
566 /// Determine the number of threads which can possibly execute concurrently.
567 /// This function is useful for determining the optimal number of threads to
568 /// use for a task.
569 /// @return The number of hardware thread contexts in the system.
570 /// @note If this value is not defined, the function returns zero (0).
571 static unsigned hardware_concurrency();
572
573 _GTHREADS_DISABLE_ASSIGNMENT(GThread)
574
575 private:
576 int mId;
577 static int tcounter; //counts live, joinable GThread instances
578 static int num_created; //counts all joinable GThread instances ever created by current process
579
580 native_handle_type mHandle; ///< Thread handle.
581 mutable GMutex mDataMutex; ///< Serializer for access to the thread private data.
582 bool mNotAThread; ///< True if this object is not a thread of execution.
583 #if defined(_GTHREADS_WIN32_)
584 unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex).
585 #endif
586 static void update_counter(int inc=1, GThread* t_update=NULL); //default: increments
587 // This is the internal thread wrapper function.
588 #if defined(_GTHREADS_WIN32_)
589 static unsigned WINAPI wrapper_function(void * aArg);
590 #else
591 static void * wrapper_function(void * aArg);
592 #endif
593 };
594
595 // Related to <ratio> - minimal to be able to support chrono.
596 typedef long long __intmax_t;
597
598 /// Minimal implementation of the \c ratio class. This class provides enough
599 /// functionality to implement some basic \c chrono classes.
600 template <__intmax_t N, __intmax_t D = 1> class ratio {
601 public:
602 static double _as_double() { return double(N) / double(D); }
603 };
604
605 /// Minimal implementation of the \c chrono namespace.
606 /// The \c chrono namespace provides types for specifying time intervals.
607 namespace chrono {
608 /// Duration template class. This class provides enough functionality to
609 /// implement \c this_thread::sleep_for().
610 template <class _Rep, class _Period = ratio<1> > class duration {
611 private:
612 _Rep rep_;
613 public:
614 typedef _Rep rep;
615 typedef _Period period;
616
617 /// Construct a duration object with the given duration.
618 template <class _Rep2>
619 explicit duration(const _Rep2& r) : rep_(r) {};
620
621 /// Return the value of the duration object.
622 rep count() const
623 {
624 return rep_;
625 }
626 };
627
628 // Standard duration types.
629 typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
630 typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds.
631 typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds.
632 typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds.
633 typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes.
634 typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
635 }
636
637 /// The namespace \c this_thread provides methods for dealing with the
638 /// calling thread.
639 namespace this_thread {
640 /// Return the thread ID of the calling thread.
641 //thread::id get_id(); //this can be slow, better not use it
642
643 /// Yield execution to another thread.
644 /// Offers the operating system the opportunity to schedule another thread
645 /// that is ready to run on the current processor.
646 inline void yield()
647 {
648 #if defined(_GTHREADS_WIN32_)
649 Sleep(0);
650 #else
651 sched_yield();
652 #endif
653 }
654
655 /// Blocks the calling thread for a period of time.
656 /// @param[in] aTime Minimum time to put the thread to sleep.
657 /// Example usage:
658 /// @code
659 /// // Sleep for 100 milliseconds
660 /// this_thread::sleep_for(chrono::milliseconds(100));
661 /// @endcode
662 /// @note Supported duration types are: nanoseconds, microseconds,
663 /// milliseconds, seconds, minutes and hours.
664 template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime)
665 {
666 #if defined(_GTHREADS_WIN32_)
667 Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
668 #else
669 usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
670 #endif
671 }
672 }
673
674 // Define/macro cleanup
675 #undef _GTHREADS_DISABLE_ASSIGNMENT
676
677 /// Fast mutex class.
678 /// This is a mutual exclusion object for synchronizing access to shared
679 /// memory areas for several threads. It is similar to the tthread::mutex class,
680 /// but instead of using system level functions, it is implemented as an atomic
681 /// spin lock with very low CPU overhead.
682 ///
683 /// The \c fast_mutex class is NOT compatible with the \c condition_variable
684 /// class (however, it IS compatible with the \c lock_guard class). It should
685 /// also be noted that the \c fast_mutex class typically does not provide
686 /// as accurate thread scheduling as a the standard \c mutex class does.
687 ///
688 /// Because of the limitations of the class, it should only be used in
689 /// situations where the mutex needs to be locked/unlocked very frequently.
690 ///
691 /// @note The "fast" version of this class relies on inline assembler language,
692 /// which is currently only supported for 32/64-bit Intel x86/AMD64 and
693 /// PowerPC architectures on a limited number of compilers (GNU g++ and MS
694 /// Visual C++).
695 /// For other architectures/compilers, system functions are used instead.
696
697 class GFastMutex {
698 public:
699 /// Constructor.
700 #if defined(_GFASTMUTEX_ASM_)
701 GFastMutex() : mLock(0) {}
702 #else
703 GFastMutex()
704 {
705 #if defined(_GTHREADS_WIN32_)
706 InitializeCriticalSection(&mHandle);
707 #elif defined(_GTHREADS_POSIX_)
708 pthread_mutex_init(&mHandle, NULL);
709 #endif
710 }
711 #endif
712
713 #if !defined(_GFASTMUTEX_ASM_)
714 /// Destructor.
715 ~GFastMutex()
716 {
717 #if defined(_GTHREADS_WIN32_)
718 DeleteCriticalSection(&mHandle);
719 #elif defined(_GTHREADS_POSIX_)
720 pthread_mutex_destroy(&mHandle);
721 #endif
722 }
723 #endif
724
725 /// Lock the mutex.
726 /// The method will block the calling thread until a lock on the mutex can
727 /// be obtained. The mutex remains locked until \c unlock() is called.
728 /// @see lock_guard
729 inline void lock()
730 {
731 #if defined(_GFASTMUTEX_ASM_)
732 bool gotLock;
733 do {
734 gotLock = try_lock();
735 if(!gotLock)
736 {
737 #if defined(_GTHREADS_WIN32_)
738 Sleep(0);
739 #elif defined(_GTHREADS_POSIX_)
740 sched_yield();
741 #endif
742 }
743 } while(!gotLock);
744 #else
745 #if defined(_GTHREADS_WIN32_)
746 EnterCriticalSection(&mHandle);
747 #elif defined(_GTHREADS_POSIX_)
748 pthread_mutex_lock(&mHandle);
749 #endif
750 #endif
751 }
752
753 /// Try to lock the mutex.
754 /// The method will try to lock the mutex. If it fails, the function will
755 /// return immediately (non-blocking).
756 /// @return \c true if the lock was acquired, or \c false if the lock could
757 /// not be acquired.
758 inline bool try_lock()
759 {
760 #if defined(_GFASTMUTEX_ASM_)
761 int oldLock;
762 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
763 asm volatile (
764 "movl $1,%%eax\n\t"
765 "xchg %%eax,%0\n\t"
766 "movl %%eax,%1\n\t"
767 : "=m" (mLock), "=m" (oldLock)
768 :
769 : "%eax", "memory"
770 );
771 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
772 int *ptrLock = &mLock;
773 __asm {
774 mov eax,1
775 mov ecx,ptrLock
776 xchg eax,[ecx]
777 mov oldLock,eax
778 }
779 #elif defined(__GNUC__) && (defined(__ppc__))
780 int newLock = 1;
781 asm volatile (
782 "\n1:\n\t"
783 "lwarx %0,0,%1\n\t"
784 "cmpwi 0,%0,0\n\t"
785 "bne- 2f\n\t"
786 "stwcx. %2,0,%1\n\t"
787 "bne- 1b\n\t"
788 "isync\n"
789 "2:\n\t"
790 : "=&r" (oldLock)
791 : "r" (&mLock), "r" (newLock)
792 : "cr0", "memory"
793 );
794 #endif
795 return (oldLock == 0);
796 #else
797 #if defined(_GTHREADS_WIN32_)
798 return TryEnterCriticalSection(&mHandle) ? true : false;
799 #elif defined(_GTHREADS_POSIX_)
800 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
801 #endif
802 #endif
803 }
804
805 /// Unlock the mutex.
806 /// If any threads are waiting for the lock on this mutex, one of them will
807 /// be unblocked.
808 inline void unlock()
809 {
810 #if defined(_GFASTMUTEX_ASM_)
811 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
812 asm volatile (
813 "movl $0,%%eax\n\t"
814 "xchg %%eax,%0\n\t"
815 : "=m" (mLock)
816 :
817 : "%eax", "memory"
818 );
819 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
820 int *ptrLock = &mLock;
821 __asm {
822 mov eax,0
823 mov ecx,ptrLock
824 xchg eax,[ecx]
825 }
826 #elif defined(__GNUC__) && (defined(__ppc__))
827 asm volatile (
828 "sync\n\t" // Replace with lwsync where possible?
829 : : : "memory"
830 );
831 mLock = 0;
832 #endif
833 #else
834 #if defined(_GTHREADS_WIN32_)
835 LeaveCriticalSection(&mHandle);
836 #elif defined(_GTHREADS_POSIX_)
837 pthread_mutex_unlock(&mHandle);
838 #endif
839 #endif
840 }
841
842 private:
843 #if defined(_GFASTMUTEX_ASM_)
844 int mLock;
845 #else
846 #if defined(_GTHREADS_WIN32_)
847 CRITICAL_SECTION mHandle;
848 #elif defined(_GTHREADS_POSIX_)
849 pthread_mutex_t mHandle;
850 #endif
851 #endif
852 };
853
854
855
856
857
858 #endif // _GTHREADS_