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, 5 months ago) by gpertea
File size: 25477 byte(s)
Log Message:
adding refactored TinyThread++ code

Line User Rev File contents
1 gpertea 156 /*
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_