#ifndef PPOOLEDTHREAD_H #define PPOOLEDTHREAD_H #include #ifdef _MSC_VER #pragma warning(disable:4100) #endif template T & get_singleton() { static T * singleton = new T; return *singleton; } template T * get_singleton_instance() { return &get_singleton(); } class PEventSync : public PObject { PCLASSINFO( PEventSync, PObject ); public: PEventSync(); void SetEvent(); void ResetEvent(); void SetAndResetEvent(); BOOL WaitEvent( const PTimeInterval & waitTime = PTimeInterval(0x7fffffff) ); protected: PMutex mutex; PSyncPoint syncPoint; BOOL triggered; }; /////////////////////////////////////////////////////////////////////// class PPooledThreadManager : public PObject { PCLASSINFO( PPooledThreadManager, PObject ); public: PPooledThreadManager(); ~PPooledThreadManager(); public: class PPooledBaseThread : public PThread { PCLASSINFO( PPooledBaseThread, PThread ); protected: PPooledBaseThread( PPooledThreadManager & manager, int stackSize = 30000, BOOL autoDeleteThread = FALSE ); ~PPooledBaseThread(); public: virtual void Main(); void SetBaseThreadId( const char * baseThreadId ){ m_BaseThreadId = baseThreadId; }; void Signal(); BOOL IsPermanentThread(); BOOL IsBusy(); BOOL WaitForCompleteEvent( DWORD wait = 0 ); void DestroyThread(); PINLINE const PString & GetBaseThreadId(){ return m_BaseThreadId; }; PDECLARE_NOTIFIER( PTimer, PPooledBaseThread, _OnSuspendTimerExpire ){ Suspend( FALSE ); }; private: PPooledThreadManager & m_Manager; PEventSync m_CompleteEvent; BOOL m_IsBusy; BOOL m_AutoDeleteThread; BOOL m_ExitThread; PSyncPoint m_SyncPoint; PString m_BaseThreadId; friend class PPooledThreadManager; }; class PPooledThreadBase : public PObject { PCLASSINFO( PPooledThreadBase, PObject ); public: PPooledThreadBase( PPooledThreadManager * manager, BOOL autoDelete = FALSE ); ~PPooledThreadBase(); virtual void Main() = 0; BOOL Resume(); virtual void Suspend( BOOL susp = TRUE ); virtual BOOL WaitForTermination( DWORD wait = UINT_MAX ); ///INLINES PINLINE const PString & GetId()const{ return m_Id; }; PINLINE const BOOL IsAutoDelete()const{ return m_IsAutoDelete; }; PINLINE void SetManager( PPooledThreadManager * manager ); PINLINE PPooledThreadManager * GetManager()const{ return m_Manager; }; protected: void InternalMain(); protected: PMutex m_InnerMutex; PPooledThreadManager * m_Manager; PPooledBaseThread * m_Thread; PString m_Id; BOOL m_IsAutoDelete; friend class PPooledBaseThread; }; PPooledBaseThread * ExecuteInThread( const PString & baseThreadId ); void DeleteSurplusThread( PPooledBaseThread * thrd ); PPooledBaseThread * GetPooledThread( const PThreadIdentifer & threadId ); protected: void EnqueueThread( PPooledBaseThread * thrd ); PPooledBaseThread * DequeueThread(); void AddActiveThread( PPooledBaseThread * thrd ); void RemoveActiveThread( PPooledBaseThread * thrd ); PString GetNextThreadId(); void AddBaseThread( PPooledThreadBase * thrd ); PPooledThreadBase * GetBaseThread( const PString & id ); void RemoveBaseThread( const PString & id ); public: PLIST( _STATIC_THREADS, PPooledBaseThread ); PQUEUE( _FREE_THREADS, PPooledBaseThread ); PDICTIONARY( _BASE_THREADS, PString, PPooledThreadBase ); PLIST( _ACTIVE_THREADS, PPooledBaseThread ); PLIST( _SURPLUS_THREADS, PPooledBaseThread ); private: PSyncPoint m_SyncPoint; BOOL m_ExitThread; PMutex m_ExecuteInThreadMutex; PMutex m_ThreadIdMutex; unsigned m_BaseThreadId; unsigned m_MaxPoolSize; unsigned m_LastUsedThreadIndex; _STATIC_THREADS m_PermanentThreads; PMutex m_ThreadPoolMutex; _FREE_THREADS m_FreeThreads; _BASE_THREADS m_BaseThreads; PMutex m_BaseThreadMutex; _ACTIVE_THREADS m_ActiveThreads; PMutex m_ActiveThreadMutex; _SURPLUS_THREADS m_SurplusThreads; PMutex m_SurplusThreadsMutex; friend class vxToolkit; friend class PPooledBaseThread; friend class PPooledThreadBase; friend class PPooledThread; }; //////////////////////////////////////////////////////////////////////// class PPooledThread : public PPooledThreadManager::PPooledThreadBase { PCLASSINFO( PPooledThread, PPooledThreadBase ); public: enum Priority { /// Will only run if all other threads are blocked. LowestPriority, /// Runs approximately half as often as normal. LowPriority, /// Normal priority for a thread. NormalPriority, /// Runs approximately twice as often as normal. HighPriority, /// Is only thread that will run, unless blocked. HighestPriority, NumPriorities }; /// Codes for thread autodelete flag enum AutoDeleteFlag { /// Automatically delete thread object on termination. AutoDeleteThread, /// Don't delete thread as it may not be on heap. NoAutoDeleteThread }; /// PThread style constructor to be compatible with PWLIB Threads PPooledThread( PINDEX stackSize = 10000, /// just for compatibility with pthreads but we can't really change the stacksize of pre-created threads int deletion = AutoDeleteThread, int priorityLevel = NormalPriority, /// Initial priority of thread. const PString & threadName = PString::Empty(), /// The name of the thread (for Debug/Trace) PPooledThreadManager * manager = NULL ); ~PPooledThread(); virtual void Main() = 0; void PrintOn( ostream & strm /// Stream to output text representation ) const; virtual BOOL WaitForTermination( DWORD wait = UINT_MAX ); virtual void Restart(); virtual void Terminate(); virtual BOOL IsTerminated(); virtual void Suspend( BOOL susp = TRUE /// Flag to suspend or resume a thread. ); virtual BOOL IsSuspended() const; static void Sleep( const PTimeInterval & delay /// Time interval to sleep for. ); virtual void SetPriority( PThread::Priority priorityLevel /// New priority for thread. ); virtual PThread::Priority GetPriority() const; virtual void SetAutoDelete( PThread::AutoDeleteFlag deletion = PThread::AutoDeleteThread /// New auto delete setting. ); void SetNoAutoDelete() { SetAutoDelete(PThread::NoAutoDeleteThread); } virtual PString GetThreadName() const; virtual void SetThreadName( const PString & name /// New name for the thread. ); virtual PThreadIdentifer GetThreadId() const; PThreadIdentifer GetCurrentThreadId(); static PPooledThread * Current(); static void Yield(); /**Create a PPooledCallbackThread executing the specified notifier. This creates a PPooledCallbackThread class that automatically executes the function defined by the PNotifier in the context of a new thread. */ static PPooledThread * Create( const PNotifier & notifier, /// Function to execute in thread. INT parameter = 0, /// Parameter value to pass to notifier. int deletion = AutoDeleteThread,/// Automatically delete PThread instance on termination of thread. int priorityLevel = NormalPriority, /// Initial priority of thread. const PString & threadName = PString::Empty(), /// The name of the thread (for Debug/Trace) PINDEX stackSize = 10000 /// Stack size on some platforms ); }; class PPooledCallbackThread : public PPooledThread { PCLASSINFO(PPooledCallbackThread, PPooledThread); public: PPooledCallbackThread( const PNotifier & notifier, INT parameter, int deletion, int priorityLevel, const PString & threadName, PINDEX stackSize ); void Main(); protected: PNotifier callback; INT parameter; }; #endif ///PPooledThread