1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWindows thread sample
4 // Author: Julian Smart(minimal)/Guilhem Lavaux(thread test)
8 // Copyright: (c) Julian Smart, Markus Holzem, Guilhem Lavaux
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
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
21 #pragma implementation "test.cpp"
22 #pragma interface "test.cpp"
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
37 #error "This sample requires thread support!"
38 #endif // wxUSE_THREADS
40 #include "wx/thread.h"
41 #include "wx/dynarray.h"
44 // Define a new application type
45 class MyApp
: public wxApp
51 WX_DEFINE_ARRAY(wxThread
*, wxArrayThread
);
53 // Define a new frame type
54 class MyFrame
: public wxFrame
58 MyFrame(wxFrame
*frame
, const wxString
& title
, int x
, int y
, int w
, int h
);
61 void WriteText(const wxString
& text
) { m_txtctrl
->WriteText(text
); }
64 void OnQuit(wxCommandEvent
& event
);
65 void OnAbout(wxCommandEvent
& event
);
66 void OnClear(wxCommandEvent
& event
);
68 void OnStartThread(wxCommandEvent
& event
);
69 void OnStopThread(wxCommandEvent
& event
);
70 void OnPauseThread(wxCommandEvent
& event
);
71 void OnResumeThread(wxCommandEvent
& event
);
73 void OnIdle(wxIdleEvent
&event
);
74 bool OnClose() { return TRUE
; }
76 // called by dying thread
77 void OnThreadExit(wxThread
*thread
);
80 wxArrayThread m_threads
;
83 // crit section protects access to the array below
84 wxCriticalSection m_critsect
;
86 // the array of threads which finished (either because they did their work
87 // or because they were explicitly stopped)
88 wxArrayInt m_aToDelete
;
90 // just some place to put our messages in
91 wxTextCtrl
*m_txtctrl
;
96 class MyThread
: public wxThread
99 MyThread(MyFrame
*frame
);
101 // thread execution starts here
102 virtual void *Entry();
104 // called when the thread exits - whether it terminates normally or is
105 // stopped with Delete() (but not when it is Kill()ed!)
106 virtual void OnExit();
108 // write something to the text control
109 void WriteText(const wxString
& text
);
116 MyThread::MyThread(MyFrame
*frame
)
123 void MyThread::WriteText(const wxString
& text
)
126 msg
<< wxTime().FormatTime() << ": " << text
;
128 // before doing any GUI calls we must ensure that this thread is the only
130 wxMutexGuiLocker guiLocker
;
132 m_frame
->WriteText(msg
);
135 void MyThread::OnExit()
137 m_frame
->OnThreadExit(this);
140 void *MyThread::Entry()
144 text
.Printf("Thread 0x%x started.\n", GetID());
147 for ( m_count
= 0; m_count
< 10; m_count
++ )
149 // check if we were asked to exit
153 text
.Printf("[%u] Thread 0x%x here.\n", m_count
, GetID());
156 // wxSleep() can't be called from non-GUI thread!
157 wxThread::Sleep(1000);
160 text
.Printf("Thread 0x%x finished.\n", GetID());
166 // ID for the menu commands
173 TEST_START_THREAD
= 203,
174 TEST_STOP_THREAD
= 204,
175 TEST_PAUSE_THREAD
= 205,
176 TEST_RESUME_THREAD
= 206
179 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
180 EVT_MENU(TEST_QUIT
, MyFrame::OnQuit
)
181 EVT_MENU(TEST_ABOUT
, MyFrame::OnAbout
)
182 EVT_MENU(TEST_CLEAR
, MyFrame::OnClear
)
183 EVT_MENU(TEST_START_THREAD
, MyFrame::OnStartThread
)
184 EVT_MENU(TEST_STOP_THREAD
, MyFrame::OnStopThread
)
185 EVT_MENU(TEST_PAUSE_THREAD
, MyFrame::OnPauseThread
)
186 EVT_MENU(TEST_RESUME_THREAD
, MyFrame::OnResumeThread
)
188 EVT_IDLE(MyFrame::OnIdle
)
191 // Create a new application object
192 IMPLEMENT_APP (MyApp
)
194 // `Main program' equivalent, creating windows and returning main app frame
197 // Create the main frame window
198 MyFrame
*frame
= new MyFrame((wxFrame
*)NULL
, "wxWindows threads sample",
202 wxMenu
*file_menu
= new wxMenu
;
204 file_menu
->Append(TEST_CLEAR
, "&Clear log");
205 file_menu
->AppendSeparator();
206 file_menu
->Append(TEST_ABOUT
, "&About");
207 file_menu
->AppendSeparator();
208 file_menu
->Append(TEST_QUIT
, "E&xit");
209 wxMenuBar
*menu_bar
= new wxMenuBar
;
210 menu_bar
->Append(file_menu
, "&File");
212 wxMenu
*thread_menu
= new wxMenu
;
213 thread_menu
->Append(TEST_START_THREAD
, "&Start a new thread");
214 thread_menu
->Append(TEST_STOP_THREAD
, "S&top a running thread");
215 thread_menu
->AppendSeparator();
216 thread_menu
->Append(TEST_PAUSE_THREAD
, "&Pause a running thread");
217 thread_menu
->Append(TEST_RESUME_THREAD
, "&Resume suspended thread");
218 menu_bar
->Append(thread_menu
, "&Thread");
219 frame
->SetMenuBar(menu_bar
);
229 // My frame constructor
230 MyFrame::MyFrame(wxFrame
*frame
, const wxString
& title
,
231 int x
, int y
, int w
, int h
)
232 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
))
236 m_txtctrl
= new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(0, 0),
237 wxTE_MULTILINE
| wxTE_READONLY
);
241 void MyFrame::OnStartThread(wxCommandEvent
& WXUNUSED(event
) )
243 MyThread
*thread
= new MyThread(this);
245 if ( thread
->Create() != wxTHREAD_NO_ERROR
)
247 wxLogError("Can't create thread!");
250 wxCriticalSectionLocker
enter(m_critsect
);
251 m_threads
.Add(thread
);
253 if ( thread
->Run() != wxTHREAD_NO_ERROR
)
255 wxLogError("Can't start thread!");
259 void MyFrame::OnStopThread(wxCommandEvent
& WXUNUSED(event
) )
261 // stop the last thread
262 if ( m_threads
.IsEmpty() )
264 wxLogError("No thread to stop!");
268 m_threads
.Last()->Delete();
272 void MyFrame::OnResumeThread(wxCommandEvent
& WXUNUSED(event
) )
274 wxCriticalSectionLocker
enter(m_critsect
);
276 // resume first suspended thread
277 size_t n
= 0, count
= m_threads
.Count();
278 while ( n
< count
&& !m_threads
[n
]->IsPaused() )
282 wxLogError("No thread to resume!");
284 m_threads
[n
]->Resume();
287 void MyFrame::OnPauseThread(wxCommandEvent
& WXUNUSED(event
) )
289 wxCriticalSectionLocker
enter(m_critsect
);
291 // pause last running thread
292 int n
= m_threads
.Count() - 1;
293 while ( n
>= 0 && !m_threads
[n
]->IsRunning() )
297 wxLogError("No thread to pause!");
299 m_threads
[n
]->Pause();
302 // set the frame title indicating the current number of threads
303 void MyFrame::OnIdle(wxIdleEvent
&event
)
305 // first remove from the array all the threads which died since last call
307 wxCriticalSectionLocker
enter(m_critsect
);
309 size_t nCount
= m_aToDelete
.Count();
310 for ( size_t n
= 0; n
< nCount
; n
++ )
312 // index should be shifted by n because we've already deleted
313 // n-1 elements from the array
314 m_threads
.Remove((size_t)m_aToDelete
[n
] - n
);
321 nCount
= m_threads
.Count();
322 for ( size_t n
= 0; n
< nCount
; n
++ )
324 if ( m_threads
[n
]->IsRunning() )
328 wxLogStatus(this, "%u threads total, %u running.", nCount
, nRunning
);
331 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
) )
333 size_t count
= m_threads
.Count();
334 for ( size_t i
= 0; i
< count
; i
++ )
336 m_threads
[i
]->Delete();
342 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
) )
344 wxMessageDialog
dialog(this, "wxWindows multithreaded application sample\n"
345 "(c) 1998 Julian Smart, Guilhem Lavaux\n"
346 "(c) 1999 Vadim Zeitlin",
347 "About wxThread sample",
348 wxOK
| wxICON_INFORMATION
);
353 void MyFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
358 void MyFrame::OnThreadExit(wxThread
*thread
)
360 int index
= m_threads
.Index(thread
);
361 wxCHECK_RET( index
!= -1, "unknown thread being deleted??" );
363 wxCriticalSectionLocker
enter(m_critsect
);
365 m_aToDelete
.Add(index
);