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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (10 years, 2 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 /* 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 pxThread* m_thread;
35
36 public:
37 EventListener_Thread()
38 {
39 m_thread = NULL;
40 }
41
42 virtual ~EventListener_Thread() throw() {}
43
44 void SetThread( pxThread& thr ) { m_thread = &thr; }
45 void SetThread( pxThread* thr ) { m_thread = thr; }
46
47 void DispatchEvent( const int& params )
48 {
49 OnThreadCleanup();
50 }
51
52 protected:
53 // Invoked by the pxThread when the thread execution is ending. This is
54 // 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 // pxThread - Helper class for the basics of starting/managing persistent threads.
63 // --------------------------------------------------------------------------------------
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 class pxThread
89 {
90 DeclareNoncopyableObject(pxThread);
91
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 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
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 virtual ~pxThread() throw();
118 pxThread( const wxString& name=L"pxThread" );
119
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 wxString GetName() const;
148 void SetName( const wxString& newname );
149
150 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 // This is called when the thread has been canceled or exits normally. The pxThread
159 // 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 void _try_virtual_invoke( void (pxThread::*method)() );
199 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 class BaseTaskThread : public pxThread
244 {
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