]> git.saurik.com Git - wxWidgets.git/blob - samples/thread/test.cpp
thread fixes for MSW (samples doesn't compile currently under !MSW, will
[wxWidgets.git] / samples / thread / test.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: test.cpp
3 // Purpose: wxWindows thread sample
4 // Author: Julian Smart(minimal)/Guilhem Lavaux(thread test)
5 // Modified by:
6 // Created: 06/16/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart, Markus Holzem, Guilhem Lavaux
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 /*
13 TODO:
14
15 1. show how SetPriority() works.
16 2. use worker threads to update progress controls instead of writing
17 messages - it will be more visual
18 */
19
20 #ifdef __GNUG__
21 #pragma implementation "test.cpp"
22 #pragma interface "test.cpp"
23 #endif
24
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 #ifndef WX_PRECOMP
33 #include "wx/wx.h"
34 #endif
35
36 #if !wxUSE_THREADS
37 #error "This sample requires thread support!"
38 #endif // wxUSE_THREADS
39
40 #include "wx/thread.h"
41 #include "wx/dynarray.h"
42 #include "wx/time.h"
43
44 // Define a new application type
45 class MyApp: public wxApp
46 {
47 public:
48 bool OnInit(void);
49 };
50
51 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
52
53 // Define a new frame type
54 class MyFrame: public wxFrame
55 {
56 public:
57 // ctor
58 MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
59
60 // operations
61 void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
62
63 // callbacks
64 void OnQuit(wxCommandEvent& event);
65 void OnAbout(wxCommandEvent& event);
66 void OnClear(wxCommandEvent& event);
67
68 void OnStartThread(wxCommandEvent& event);
69 void OnStopThread(wxCommandEvent& event);
70 void OnPauseThread(wxCommandEvent& event);
71 void OnResumeThread(wxCommandEvent& event);
72
73 void OnIdle(wxIdleEvent &event);
74 bool OnClose() { return TRUE; }
75
76 // called by dying thread
77 void OnThreadExit(wxThread *thread);
78
79 public:
80 wxArrayThread m_threads;
81
82 private:
83 void DeleteThread(size_t index);
84
85 // crit section protects access to the array below
86 wxCriticalSection m_critsect;
87 wxArrayInt m_aToDelete;
88
89 wxTextCtrl *m_txtctrl;
90
91 DECLARE_EVENT_TABLE()
92 };
93
94 class MyThread : public wxThread
95 {
96 public:
97 MyThread(MyFrame *frame);
98
99 // thread execution starts here
100 virtual void *Entry();
101
102 // called when the thread exits - whether
103 virtual void OnExit();
104
105 // write something to the text control
106 void WriteText(const wxString& text);
107
108 public:
109 size_t m_count;
110 MyFrame *m_frame;
111 };
112
113 MyThread::MyThread(MyFrame *frame)
114 : wxThread()
115 {
116 m_count = 0;
117 m_frame = frame;
118 }
119
120 void MyThread::WriteText(const wxString& text)
121 {
122 wxString msg;
123 msg << wxTime().FormatTime() << ": " << text;
124
125 // before doing any GUI calls we must ensure that this thread is the only
126 // one doing it!
127 wxMutexGuiLocker guiLocker;
128
129 m_frame->WriteText(msg);
130 }
131
132 void MyThread::OnExit()
133 {
134 m_frame->OnThreadExit(this);
135 }
136
137 void *MyThread::Entry()
138 {
139 wxString text;
140
141 DeferDestroy(TRUE);
142
143 text.Printf("Thread 0x%x started.\n", GetID());
144 WriteText(text);
145
146 for ( m_count = 0; m_count < 10; m_count++ )
147 {
148 // check if we were asked to exit
149 if ( TestDestroy() )
150 break;
151
152 text.Printf("[%u] Thread 0x%x here.\n", m_count, GetID());
153 WriteText(text);
154
155 #ifdef __WXMSW__
156 ::Sleep(1000);
157 #else
158 wxSleep(1);
159 #endif
160 }
161
162 text.Printf("Thread 0x%x finished.\n", GetID());
163 WriteText(text);
164
165 return NULL;
166 }
167
168 // ID for the menu commands
169 enum
170 {
171 TEST_QUIT = 1,
172 TEST_TEXT = 101,
173 TEST_ABOUT = 102,
174 TEST_CLEAR = 103,
175 TEST_START_THREAD = 203,
176 TEST_STOP_THREAD = 204,
177 TEST_PAUSE_THREAD = 205,
178 TEST_RESUME_THREAD = 206
179 };
180
181 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
182 EVT_MENU(TEST_QUIT, MyFrame::OnQuit)
183 EVT_MENU(TEST_ABOUT, MyFrame::OnAbout)
184 EVT_MENU(TEST_CLEAR, MyFrame::OnClear)
185 EVT_MENU(TEST_START_THREAD, MyFrame::OnStartThread)
186 EVT_MENU(TEST_STOP_THREAD, MyFrame::OnStopThread)
187 EVT_MENU(TEST_PAUSE_THREAD, MyFrame::OnPauseThread)
188 EVT_MENU(TEST_RESUME_THREAD, MyFrame::OnResumeThread)
189
190 EVT_IDLE(MyFrame::OnIdle)
191 END_EVENT_TABLE()
192
193 // Create a new application object
194 IMPLEMENT_APP (MyApp)
195
196 // `Main program' equivalent, creating windows and returning main app frame
197 bool MyApp::OnInit()
198 {
199 // Create the main frame window
200 MyFrame *frame = new MyFrame((wxFrame *)NULL, "wxWindows threads sample",
201 50, 50, 450, 340);
202
203 // Make a menubar
204 wxMenu *file_menu = new wxMenu;
205
206 file_menu->Append(TEST_CLEAR, "&Clear log");
207 file_menu->AppendSeparator();
208 file_menu->Append(TEST_ABOUT, "&About");
209 file_menu->AppendSeparator();
210 file_menu->Append(TEST_QUIT, "E&xit");
211 wxMenuBar *menu_bar = new wxMenuBar;
212 menu_bar->Append(file_menu, "&File");
213
214 wxMenu *thread_menu = new wxMenu;
215 thread_menu->Append(TEST_START_THREAD, "&Start a new thread");
216 thread_menu->Append(TEST_STOP_THREAD, "S&top a running thread");
217 thread_menu->AppendSeparator();
218 thread_menu->Append(TEST_PAUSE_THREAD, "&Pause a running thread");
219 thread_menu->Append(TEST_RESUME_THREAD, "&Resume suspended thread");
220 menu_bar->Append(thread_menu, "&Thread");
221 frame->SetMenuBar(menu_bar);
222
223 // Show the frame
224 frame->Show(TRUE);
225
226 SetTopWindow(frame);
227
228 return TRUE;
229 }
230
231 // My frame constructor
232 MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
233 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
234 {
235 CreateStatusBar();
236
237 m_txtctrl = new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(0, 0),
238 wxTE_MULTILINE | wxTE_READONLY);
239
240 }
241
242 void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
243 {
244 MyThread *thread = new MyThread(this);
245
246 thread->Create();
247
248 wxCriticalSectionLocker enter(m_critsect);
249 m_threads.Add(thread);
250 }
251
252 void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
253 {
254 int no_thrd = m_threads.Count() - 1;
255
256 if ( no_thrd < 0 )
257 {
258 wxLogError("No thread to stop!");
259
260 return;
261 }
262
263 DeleteThread(no_thrd);
264 }
265
266 void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
267 {
268 wxCriticalSectionLocker enter(m_critsect);
269
270 // resume first suspended thread
271 size_t n = 0;
272 while ( n < m_threads.Count() && m_threads[n]->IsPaused() )
273 n--;
274
275 if ( n < 0 )
276 wxLogError("No thread to resume!");
277 else
278 m_threads[n]->Resume();
279 }
280
281 void MyFrame::OnPauseThread(wxCommandEvent& WXUNUSED(event) )
282 {
283 wxCriticalSectionLocker enter(m_critsect);
284
285 // pause last running thread
286 int n = m_threads.Count() - 1;
287 while ( n >= 0 && !m_threads[n]->IsRunning() )
288 n--;
289
290 if ( n < 0 )
291 wxLogError("No thread to pause!");
292 else
293 m_threads[n]->Pause();
294 }
295
296 // set the frame title indicating the current number of threads
297 void MyFrame::OnIdle(wxIdleEvent &event)
298 {
299 // first remove from the array all the threads which died since last call
300 {
301 wxCriticalSectionLocker enter(m_critsect);
302
303 size_t nCount = m_aToDelete.Count();
304 for ( size_t n = 0; n < nCount; n++ )
305 DeleteThread((size_t)m_aToDelete[n]);
306
307 m_aToDelete.Empty();
308 }
309
310 size_t nRunning = 0,
311 nCount = m_threads.Count();
312 for ( size_t n = 0; n < nCount; n++ )
313 {
314 if ( m_threads[n]->IsRunning() )
315 nRunning++;
316 }
317
318 wxLogStatus(this, "%u threads total, %u running.", nCount, nRunning);
319 }
320
321 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
322 {
323 for ( size_t i = 0; i < m_threads.Count(); i++ )
324 delete m_threads[i];
325
326 Close(TRUE);
327 }
328
329 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
330 {
331 wxMessageDialog dialog(this, "wxThread sample (based on minimal)\n"
332 "Julian Smart, Guilhem Lavaux, Vadim Zeitlin",
333 "About wxThread sample",
334 wxOK | wxICON_INFORMATION);
335
336 dialog.ShowModal();
337 }
338
339 void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
340 {
341 m_txtctrl->Clear();
342 }
343
344 void MyFrame::OnThreadExit(wxThread *thread)
345 {
346 int index = m_threads.Index(thread);
347 wxCHECK_RET( index != -1, "unknown thread being deleted??" );
348
349 wxCriticalSectionLocker enter(m_critsect);
350
351 m_aToDelete.Add(index);
352 }
353
354 void MyFrame::DeleteThread(size_t index)
355 {
356 delete m_threads[index];
357 m_threads.Remove(index);
358 }