ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GThreads.h
(Generate patch)
# Line 40 | Line 40
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
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
# Line 48 | Line 48
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
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.
# Line 85 | Line 86
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>
# Line 99 | Line 108
108   /// TinyThread++ version (major number).
109   #define TINYTHREAD_VERSION_MAJOR 1
110   /// TinyThread++ version (minor number).
111 < #define TINYTHREAD_VERSION_MINOR 0
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++0x compiler?
115 > // Do we have a fully featured C++11 compiler?
116   #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
117 <  #define _GTHREADS_CPP0X_
117 >  #define _GTHREADS_CPP11_
118   #endif
119  
120 < // ...at least partial C++0x?
121 < #if defined(_GTHREADS_CPP0X_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
122 <  #define _GTHREADS_CPP0X_PARTIAL_
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_CPP0X_PARTIAL_
126 > #ifdef _GTHREADS_CPP11_PARTIAL_
127    #define _GTHREADS_DISABLE_ASSIGNMENT(name) \
128        name(const name&) = delete; \
129        name& operator=(const name&) = delete;
# Line 134 | Line 143
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++0x standard
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++0x
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
# Line 145 | Line 154
154   /// not support this directive.
155   /// @hideinitializer
156  
157 < #if !defined(_GTHREADS_CPP0X_) && !defined(thread_local)
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
# Line 161 | Line 170
170  
171   /// Main name space for TinyThread++.
172   /// This namespace is more or less equivalent to the \c std namespace for the
173 < /// C++0x thread classes. For instance, the tthread::mutex class corresponds to
173 > /// C++11 thread classes. For instance, the tthread::mutex class corresponds to
174   /// the std::mutex class.
175   //namespace tthread {
176  
# Line 339 | Line 348
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
# Line 477 | Line 665
665        pthread_cond_broadcast(&mHandle);
666      }
667   #endif
480
668      _GTHREADS_DISABLE_ASSIGNMENT(GConditionVar)
482
669    private:
670   #if defined(_GTHREADS_WIN32_)
671      void _wait();
# Line 492 | Line 678
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:
# Line 500 | Line 694
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 \c thread object without an associated thread of execution
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_)
# Line 511 | Line 716
716      {}
717  
718      /// Thread starting constructor.
719 <    /// Construct a \c thread object with a new thread of execution.
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);
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()
# Line 533 | Line 744
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  
# Line 553 | Line 770
770      }
771      static int num_running() {
772          //return number of running (live) threads
773 <      static GMutex vLock;
774 <      GLockGuard<GMutex> guard(vLock);
775 <          int r=tcounter;
776 <          return r;
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
# Line 573 | Line 790
790      _GTHREADS_DISABLE_ASSIGNMENT(GThread)
791  
792    private:
793 <    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
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_)
# Line 674 | Line 882
882   // Define/macro cleanup
883   #undef _GTHREADS_DISABLE_ASSIGNMENT
884  
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
885  
886  
887   #endif // _GTHREADS_

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines