]> git.saurik.com Git - wxWidgets.git/blame - tests/thread/misc.cpp
Remove redundant lines from Inno Setup file.
[wxWidgets.git] / tests / thread / misc.cpp
CommitLineData
1f5496a0
FM
1///////////////////////////////////////////////////////////////////////////////
2// Name: tests/thread/misc.cpp
3// Purpose: Miscellaneous wxThread test cases
4// Author: Francesco Montorsi (extracted from console sample)
5// Created: 2010-05-10
6// RCS-ID: $Id$
7// Copyright: (c) 2010 wxWidgets team
8///////////////////////////////////////////////////////////////////////////////
9
10// ----------------------------------------------------------------------------
11// headers
12// ----------------------------------------------------------------------------
13
14#include "testprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
20#ifndef WX_PRECOMP
21#endif // WX_PRECOMP
22
23#include "wx/thread.h"
5d029a1d 24#include "wx/utils.h"
1f5496a0
FM
25
26// ----------------------------------------------------------------------------
27// globals
28// ----------------------------------------------------------------------------
29
30static size_t gs_counter = (size_t)-1;
31static wxCriticalSection gs_critsect;
32static wxSemaphore gs_cond;
33
34class MyJoinableThread : public wxThread
35{
36public:
37 MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE)
38 { m_n = n; Create(); }
39
40 // thread execution starts here
41 virtual ExitCode Entry();
42
43private:
44 size_t m_n;
45};
46
47wxThread::ExitCode MyJoinableThread::Entry()
48{
49 unsigned long res = 1;
50 for ( size_t n = 1; n < m_n; n++ )
51 {
52 res *= n;
53
54 // it's a loooong calculation :-)
55 wxMilliSleep(100);
56 }
57
58 return (ExitCode)res;
59}
60
61class MyDetachedThread : public wxThread
62{
63public:
64 MyDetachedThread(size_t n, wxChar ch)
65 {
66 m_n = n;
67 m_ch = ch;
68 m_cancelled = false;
69
70 Create();
71 }
72
73 // thread execution starts here
74 virtual ExitCode Entry();
75
76 // and stops here
77 virtual void OnExit();
78
79private:
80 size_t m_n; // number of characters to write
81 wxChar m_ch; // character to write
82
83 bool m_cancelled; // false if we exit normally
84};
85
86wxThread::ExitCode MyDetachedThread::Entry()
87{
88 {
89 wxCriticalSectionLocker lock(gs_critsect);
90 if ( gs_counter == (size_t)-1 )
91 gs_counter = 1;
92 else
93 gs_counter++;
94 }
95
96 for ( size_t n = 0; n < m_n; n++ )
97 {
98 if ( TestDestroy() )
99 {
100 m_cancelled = true;
101
102 break;
103 }
104
105 //wxPutchar(m_ch);
106 //fflush(stdout);
107
5d029a1d 108 wxMilliSleep(100);
1f5496a0
FM
109 }
110
111 return 0;
112}
113
114void MyDetachedThread::OnExit()
115{
116 //wxLogTrace(wxT("thread"), wxT("Thread %ld is in OnExit"), GetId());
117
118 wxCriticalSectionLocker lock(gs_critsect);
119 if ( !--gs_counter && !m_cancelled )
120 gs_cond.Post();
121}
122
123class MyWaitingThread : public wxThread
124{
125public:
126 MyWaitingThread( wxMutex *mutex, wxCondition *condition )
127 {
128 m_mutex = mutex;
129 m_condition = condition;
130
131 Create();
132 }
133
134 virtual ExitCode Entry()
135 {
136 //wxPrintf(wxT("Thread %lu has started running.\n"), GetId());
137 gs_cond.Post();
138
139 //wxPrintf(wxT("Thread %lu starts to wait...\n"), GetId());
140
141 m_mutex->Lock();
142 m_condition->Wait();
143 m_mutex->Unlock();
144
145 //wxPrintf(wxT("Thread %lu finished to wait, exiting.\n"), GetId());
146
147 return 0;
148 }
149
150private:
151 wxMutex *m_mutex;
152 wxCondition *m_condition;
153};
154
155// semaphore tests
156#include "wx/datetime.h"
157
158class MySemaphoreThread : public wxThread
159{
160public:
161 MySemaphoreThread(int i, wxSemaphore *sem)
162 : wxThread(wxTHREAD_JOINABLE),
163 m_sem(sem),
164 m_i(i)
165 {
166 Create();
167 }
168
169 virtual ExitCode Entry()
170 {
a2ae6625
VZ
171 wxUnusedVar(m_i);
172
1f5496a0
FM
173 //wxPrintf(wxT("%s: Thread #%d (%ld) starting to wait for semaphore...\n"),
174 // wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
175
176 m_sem->Wait();
177
178 //wxPrintf(wxT("%s: Thread #%d (%ld) acquired the semaphore.\n"),
179 // wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
180
181 Sleep(1000);
182
183 //wxPrintf(wxT("%s: Thread #%d (%ld) releasing the semaphore.\n"),
184 // wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
185
186 m_sem->Post();
187
188 return 0;
189 }
190
191private:
192 wxSemaphore *m_sem;
193 int m_i;
194};
195
196WX_DEFINE_ARRAY_PTR(wxThread *, ArrayThreads);
197
198// ----------------------------------------------------------------------------
199// test class
200// ----------------------------------------------------------------------------
201
202class MiscThreadTestCase : public CppUnit::TestCase
203{
204public:
205 MiscThreadTestCase();
206
207private:
208 CPPUNIT_TEST_SUITE( MiscThreadTestCase );
209 CPPUNIT_TEST( TestJoinable );
210 CPPUNIT_TEST( TestDetached );
211 CPPUNIT_TEST( TestThreadSuspend );
212 CPPUNIT_TEST( TestThreadDelete );
89a76d5d 213 CPPUNIT_TEST( TestThreadRun );
1f5496a0
FM
214 CPPUNIT_TEST( TestThreadConditions );
215 CPPUNIT_TEST( TestSemaphore );
216 CPPUNIT_TEST_SUITE_END();
217
218 void TestJoinable();
219 void TestDetached();
220 void TestSemaphore();
221
222 void TestThreadSuspend();
223 void TestThreadDelete();
89a76d5d 224 void TestThreadRun();
1f5496a0
FM
225 void TestThreadConditions();
226
227 DECLARE_NO_COPY_CLASS(MiscThreadTestCase)
228};
229
230// register in the unnamed registry so that these tests are run by default
231CPPUNIT_TEST_SUITE_REGISTRATION( MiscThreadTestCase );
232
e3778b4d 233// also include in its own registry so that these tests can be run alone
1f5496a0
FM
234CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MiscThreadTestCase, "MiscThreadTestCase" );
235
236MiscThreadTestCase::MiscThreadTestCase()
237{
238 int nCPUs = wxThread::GetCPUCount();
239 if ( nCPUs != -1 )
240 wxThread::SetConcurrency(nCPUs);
241}
242
243void MiscThreadTestCase::TestJoinable()
244{
245 // calc 10! in the background
246 MyJoinableThread thread(10);
247 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread.Run() );
248 CPPUNIT_ASSERT_EQUAL( 362880, (unsigned long)thread.Wait() );
249}
250
251void MiscThreadTestCase::TestDetached()
252{
253 static const size_t nThreads = 3;
254 MyDetachedThread *threads[nThreads];
255
256 size_t n;
257 for ( n = 0; n < nThreads; n++ )
258 {
259 threads[n] = new MyDetachedThread(10, 'A' + n);
260 }
261
90e95e61
VZ
262 threads[0]->SetPriority(wxPRIORITY_MIN);
263 threads[1]->SetPriority(wxPRIORITY_MAX);
1f5496a0
FM
264
265 for ( n = 0; n < nThreads; n++ )
266 {
267 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() );
268 }
269
270 // wait until all threads terminate
271 CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
272}
273
274void MiscThreadTestCase::TestSemaphore()
275{
276 static const int SEM_LIMIT = 3;
277
278 wxSemaphore sem(SEM_LIMIT, SEM_LIMIT);
279 ArrayThreads threads;
280
281 for ( int i = 0; i < 3*SEM_LIMIT; i++ )
282 {
283 threads.Add(new MySemaphoreThread(i, &sem));
284 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads.Last()->Run() );
285 }
286
287 for ( size_t n = 0; n < threads.GetCount(); n++ )
288 {
289 CPPUNIT_ASSERT_EQUAL( 0, (long)threads[n]->Wait() );
290 delete threads[n];
291 }
292}
293
294void MiscThreadTestCase::TestThreadSuspend()
295{
296 MyDetachedThread *thread = new MyDetachedThread(15, 'X');
297
298 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Run() );
299
300 // this is for this demo only, in a real life program we'd use another
301 // condition variable which would be signaled from wxThread::Entry() to
302 // tell us that the thread really started running - but here just wait a
303 // bit and hope that it will be enough (the problem is, of course, that
304 // the thread might still not run when we call Pause() which will result
305 // in an error)
5d029a1d 306 wxMilliSleep(300);
1f5496a0
FM
307
308 for ( size_t n = 0; n < 3; n++ )
309 {
310 thread->Pause();
311
312 if ( n > 0 )
313 {
314 // don't sleep but resume immediately the first time
5d029a1d 315 wxMilliSleep(300);
1f5496a0
FM
316 }
317
318 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Resume() );
319 }
320
321 // wait until the thread terminates
322 CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
323}
324
325void MiscThreadTestCase::TestThreadDelete()
326{
89a76d5d 327 // FIXME:
1f5496a0
FM
328 // As above, using Sleep() is only for testing here - we must use some
329 // synchronisation object instead to ensure that the thread is still
330 // running when we delete it - deleting a detached thread which already
331 // terminated will lead to a crash!
332
333 MyDetachedThread *thread0 = new MyDetachedThread(30, 'W');
334 CPPUNIT_ASSERT_EQUAL( wxTHREAD_MISC_ERROR, thread0->Delete() );
335 // delete a thread which didn't start to run yet.
336
337 MyDetachedThread *thread1 = new MyDetachedThread(30, 'Y');
338 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1->Run() );
5d029a1d 339 wxMilliSleep(300);
1f5496a0
FM
340 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1->Delete() );
341 // delete a running thread
342
343 MyDetachedThread *thread2 = new MyDetachedThread(30, 'Z');
344 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Run() );
5d029a1d 345 wxMilliSleep(300);
1f5496a0
FM
346 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Pause() );
347 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Delete() );
348 // delete a sleeping thread
349
350 MyJoinableThread thread3(20);
351 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread3.Run() );
352 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread3.Delete() );
89a76d5d 353 // delete a joinable running thread
1f5496a0
FM
354
355 MyJoinableThread thread4(2);
356 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread4.Run() );
5d029a1d 357 wxMilliSleep(300);
1f5496a0
FM
358 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread4.Delete() );
359 // delete a joinable thread which already terminated
360}
361
89a76d5d
FM
362void MiscThreadTestCase::TestThreadRun()
363{
364 MyJoinableThread thread1(2);
365 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1.Run() );
366 thread1.Wait(); // wait until the thread ends
367
368 // verify that running twice the same thread fails
369 WX_ASSERT_FAILS_WITH_ASSERT( thread1.Run() );
370}
371
1f5496a0
FM
372void MiscThreadTestCase::TestThreadConditions()
373{
374 wxMutex mutex;
375 wxCondition condition(mutex);
376
377 // otherwise its difficult to understand which log messages pertain to
378 // which condition
379 //wxLogTrace(wxT("thread"), wxT("Local condition var is %08x, gs_cond = %08x"),
380 // condition.GetId(), gs_cond.GetId());
381
382 // create and launch threads
383 MyWaitingThread *threads[10];
384
385 size_t n;
386 for ( n = 0; n < WXSIZEOF(threads); n++ )
387 {
388 threads[n] = new MyWaitingThread( &mutex, &condition );
389 }
390
391 for ( n = 0; n < WXSIZEOF(threads); n++ )
392 {
393 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() );
394 }
395
396 // wait until all threads run
397 // NOTE: main thread is waiting for the other threads to start
398 size_t nRunning = 0;
399 while ( nRunning < WXSIZEOF(threads) )
400 {
401 CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
402
403 nRunning++;
404
405 // note that main thread is already running
406 }
407
5d029a1d 408 wxMilliSleep(500);
1f5496a0
FM
409
410#if 1
411 // now wake one of them up
412 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Signal() );
413#endif
414
5d029a1d 415 wxMilliSleep(200);
1f5496a0
FM
416
417 // wake all the (remaining) threads up, so that they can exit
418 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Broadcast() );
419
420 // give them time to terminate (dirty!)
5d029a1d 421 wxMilliSleep(500);
1f5496a0 422}