ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GThreads.h
Revision: 310
Committed: Fri Mar 22 20:06:27 2013 UTC (5 years, 11 months ago) by gpertea
File size: 26558 byte(s)
Log Message:
sync with igm repo

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