/[pcsx2_0.9.7]/trunk/common/include/Utilities/PersistentThread.h
ViewVC logotype

Annotation of /trunk/common/include/Utilities/PersistentThread.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months ago) by william
File MIME type: text/plain
File size: 10687 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16     #pragma once
17    
18     #include "Threading.h"
19     #include "ScopedPtrMT.h"
20     #include "EventSource.h"
21    
22     namespace Threading
23     {
24    
25     // --------------------------------------------------------------------------------------
26     // ThreadDeleteEvent
27     // --------------------------------------------------------------------------------------
28     class EventListener_Thread : public IEventDispatcher<int>
29     {
30     public:
31     typedef int EvtParams;
32    
33     protected:
34 william 62 pxThread* m_thread;
35 william 31
36     public:
37     EventListener_Thread()
38     {
39     m_thread = NULL;
40     }
41    
42     virtual ~EventListener_Thread() throw() {}
43    
44 william 62 void SetThread( pxThread& thr ) { m_thread = &thr; }
45     void SetThread( pxThread* thr ) { m_thread = thr; }
46 william 31
47     void DispatchEvent( const int& params )
48     {
49     OnThreadCleanup();
50     }
51    
52     protected:
53 william 62 // Invoked by the pxThread when the thread execution is ending. This is
54 william 31 // typically more useful than a delete listener since the extended thread information
55     // provided by virtualized functions/methods will be available.
56     // Important! This event is executed *by the thread*, so care must be taken to ensure
57     // thread sync when necessary (posting messages to the main thread, etc).
58     virtual void OnThreadCleanup()=0;
59     };
60    
61     // --------------------------------------------------------------------------------------
62 william 62 // pxThread - Helper class for the basics of starting/managing persistent threads.
63 william 31 // --------------------------------------------------------------------------------------
64     // This class is meant to be a helper for the typical threading model of "start once and
65     // reuse many times." This class incorporates a lot of extra overhead in stopping and
66     // starting threads, but in turn provides most of the basic thread-safety and event-handling
67     // functionality needed for a threaded operation. In practice this model is usually an
68     // ideal one for efficiency since Operating Systems themselves typically subscribe to a
69     // design where sleeping, suspending, and resuming threads is very efficient, but starting
70     // new threads has quite a bit of overhead.
71     //
72     // To use this as a base class for your threaded procedure, overload the following virtual
73     // methods:
74     // void OnStart();
75     // void ExecuteTaskInThread();
76     // void OnCleanupInThread();
77     //
78     // Use the public methods Start() and Cancel() to start and shutdown the thread, and use
79     // m_sem_event internally to post/receive events for the thread (make a public accessor for
80     // it in your derived class if your thread utilizes the post).
81     //
82     // Notes:
83     // * Constructing threads as static global vars isn't recommended since it can potentially
84     // confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
85     // no dependency options for ensuring correct static var initializations). Use heap
86     // allocation to create thread objects instead.
87     //
88 william 62 class pxThread
89 william 31 {
90 william 62 DeclareNoncopyableObject(pxThread);
91 william 31
92     friend void pxYield( int ms );
93    
94     protected:
95     wxString m_name; // diagnostic name for our thread.
96     pthread_t m_thread;
97     uptr m_native_id; // typically an id, but implementing platforms can do whatever.
98     uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
99    
100     Semaphore m_sem_event; // general wait event that's needed by most threads
101     Semaphore m_sem_startup; // startup sync tool
102 william 62 Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
103     MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
104     Mutex m_mtx_ThreadName;
105 william 31
106     volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
107     volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
108    
109     // exception handle, set non-NULL if the thread terminated with an exception
110     // Use RethrowException() to re-throw the exception using its original exception type.
111     ScopedPtrMT<BaseException> m_except;
112    
113     EventSource<EventListener_Thread> m_evtsrc_OnDelete;
114    
115    
116     public:
117 william 62 virtual ~pxThread() throw();
118     pxThread( const wxString& name=L"pxThread" );
119 william 31
120     pthread_t GetId() const { return m_thread; }
121     u64 GetCpuTime() const;
122    
123     virtual void Start();
124     virtual void Cancel( bool isBlocking = true );
125     virtual bool Cancel( const wxTimeSpan& timeout );
126     virtual bool Detach();
127     virtual void Block();
128     virtual bool Block( const wxTimeSpan& timeout );
129     virtual void RethrowException() const;
130    
131     void AddListener( EventListener_Thread& evt );
132     void AddListener( EventListener_Thread* evt )
133     {
134     if( evt == NULL ) return;
135     AddListener( *evt );
136     }
137    
138     void WaitOnSelf( Semaphore& mutex ) const;
139     void WaitOnSelf( Mutex& mutex ) const;
140     bool WaitOnSelf( Semaphore& mutex, const wxTimeSpan& timeout ) const;
141     bool WaitOnSelf( Mutex& mutex, const wxTimeSpan& timeout ) const;
142    
143     bool IsRunning() const;
144     bool IsSelf() const;
145     bool HasPendingException() const { return !!m_except; }
146    
147 william 62 wxString GetName() const;
148     void SetName( const wxString& newname );
149    
150 william 31 protected:
151     // Extending classes should always implement your own OnStart(), which is called by
152     // Start() once necessary locks have been obtained. Do not override Start() directly
153     // unless you're really sure that's what you need to do. ;)
154     virtual void OnStart();
155    
156     virtual void OnStartInThread();
157    
158 william 62 // This is called when the thread has been canceled or exits normally. The pxThread
159 william 31 // automatically binds it to the pthread cleanup routines as soon as the thread starts.
160     virtual void OnCleanupInThread();
161    
162     // Implemented by derived class to perform actual threaded task!
163     virtual void ExecuteTaskInThread()=0;
164    
165     void TestCancel() const;
166    
167     // Yields this thread to other threads and checks for cancellation. A sleeping thread should
168     // always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
169     // or better yet, disable cancellation of the thread completely with DisableCancellation().
170     //
171     // Parameters:
172     // ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
173     // depending on operating system/platform). If ms is 0 or unspecified, then a single
174     // timeslice is yielded to other contending threads. If no threads are contending for
175     // time when ms==0, then no yield is done, but cancellation is still tested.
176     void Yield( int ms = 0 )
177     {
178     pxAssert( IsSelf() );
179     Threading::Sleep( ms );
180     TestCancel();
181     }
182    
183     void FrankenMutex( Mutex& mutex );
184    
185     bool AffinityAssert_AllowFromSelf( const DiagnosticOrigin& origin ) const;
186     bool AffinityAssert_DisallowFromSelf( const DiagnosticOrigin& origin ) const;
187    
188     // ----------------------------------------------------------------------------
189     // Section of methods for internal use only.
190    
191     void _platform_specific_OnStartInThread();
192     void _platform_specific_OnCleanupInThread();
193     bool _basecancel();
194     void _selfRunningTest( const wxChar* name ) const;
195     void _DoSetThreadName( const wxString& name );
196     void _DoSetThreadName( const char* name );
197     void _internal_execute();
198 william 62 void _try_virtual_invoke( void (pxThread::*method)() );
199 william 31 void _ThreadCleanup();
200    
201     static void* _internal_callback( void* func );
202     static void _pt_callback_cleanup( void* handle );
203     };
204    
205    
206     // --------------------------------------------------------------------------------------
207     // BaseTaskThread
208     // --------------------------------------------------------------------------------------
209     // an abstract base class which provides simple parallel execution of single tasks.
210     //
211     // FIXME: This class is incomplete and untested! Don't use, unless you want to fix it
212     // while you're at it. :D
213     //
214     // Implementation:
215     // To use this class your derived class will need to implement its own Task() function
216     // and also a "StartTask( parameters )" function which suits the need of your task, along
217     // with any local variables your task needs to do its job. You may additionally want to
218     // implement a "GetResult()" function, which would be a combination of WaitForResult()
219     // and a return value of the computational result.
220     //
221     // Thread Safety:
222     // If operating on local variables, you must execute WaitForResult() before leaving the
223     // variable scope -- or alternatively have your StartTask() implementation make full
224     // copies of dependent data. Also, by default PostTask() always assumes the previous
225     // task has completed. If your system can post a new task before the previous one has
226     // completed, then it needs to explicitly call WaitForResult() or provide a mechanism
227     // to cancel the previous task (which is probably more work than it's worth).
228     //
229     // Performance notes:
230     // * Remember that thread creation is generally slow, so you should make your object
231     // instance once early and then feed it tasks repeatedly over the course of program
232     // execution.
233     //
234     // * For threading to be a successful speedup, the task being performed should be as lock
235     // free as possible. For example using STL containers in parallel usually fails to
236     // yield any speedup due to the gratuitous amount of locking that the STL performs
237     // internally.
238     //
239     // * The best application of tasking threads is to divide a large loop over a linear array
240     // into smaller sections. For example, if you have 20,000 items to process, the task
241     // can be divided into two threads of 10,000 items each.
242     //
243 william 62 class BaseTaskThread : public pxThread
244 william 31 {
245     protected:
246     volatile bool m_Done;
247     volatile bool m_TaskPending;
248     Semaphore m_post_TaskComplete;
249     Mutex m_lock_TaskComplete;
250    
251     public:
252     virtual ~BaseTaskThread() throw() {}
253     BaseTaskThread() :
254     m_Done( false )
255     , m_TaskPending( false )
256     , m_post_TaskComplete()
257     {
258     }
259    
260     void Block();
261     void PostTask();
262     void WaitForResult();
263    
264     protected:
265     // Abstract method run when a task has been posted. Implementing classes should do
266     // all your necessary processing work here.
267     virtual void Task()=0;
268    
269     virtual void ExecuteTaskInThread();
270     };
271     }

  ViewVC Help
Powered by ViewVC 1.1.22