1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/thread/misc.cpp
3 // Purpose: Miscellaneous wxThread test cases
4 // Author: Francesco Montorsi (extracted from console sample)
6 // Copyright: (c) 2010 wxWidgets team
7 ///////////////////////////////////////////////////////////////////////////////
9 // ----------------------------------------------------------------------------
11 // ----------------------------------------------------------------------------
22 #include "wx/thread.h"
25 // ----------------------------------------------------------------------------
27 // ----------------------------------------------------------------------------
29 static size_t gs_counter
= (size_t)-1;
30 static wxCriticalSection gs_critsect
;
31 static wxSemaphore gs_cond
;
33 class MyJoinableThread
: public wxThread
36 MyJoinableThread(size_t n
) : wxThread(wxTHREAD_JOINABLE
)
37 { m_n
= n
; Create(); }
39 // thread execution starts here
40 virtual ExitCode
Entry();
46 wxThread::ExitCode
MyJoinableThread::Entry()
48 unsigned long res
= 1;
49 for ( size_t n
= 1; n
< m_n
; n
++ )
53 // it's a loooong calculation :-)
60 class MyDetachedThread
: public wxThread
63 MyDetachedThread(size_t n
, wxChar ch
)
72 // thread execution starts here
73 virtual ExitCode
Entry();
76 virtual void OnExit();
79 size_t m_n
; // number of characters to write
80 wxChar m_ch
; // character to write
82 bool m_cancelled
; // false if we exit normally
85 wxThread::ExitCode
MyDetachedThread::Entry()
88 wxCriticalSectionLocker
lock(gs_critsect
);
89 if ( gs_counter
== (size_t)-1 )
95 for ( size_t n
= 0; n
< m_n
; n
++ )
113 void MyDetachedThread::OnExit()
115 //wxLogTrace(wxT("thread"), wxT("Thread %ld is in OnExit"), GetId());
117 wxCriticalSectionLocker
lock(gs_critsect
);
118 if ( !--gs_counter
&& !m_cancelled
)
122 class MyWaitingThread
: public wxThread
125 MyWaitingThread( wxMutex
*mutex
, wxCondition
*condition
)
128 m_condition
= condition
;
133 virtual ExitCode
Entry()
135 //wxPrintf(wxT("Thread %lu has started running.\n"), GetId());
138 //wxPrintf(wxT("Thread %lu starts to wait...\n"), GetId());
144 //wxPrintf(wxT("Thread %lu finished to wait, exiting.\n"), GetId());
151 wxCondition
*m_condition
;
155 #include "wx/datetime.h"
157 class MySemaphoreThread
: public wxThread
160 MySemaphoreThread(int i
, wxSemaphore
*sem
)
161 : wxThread(wxTHREAD_JOINABLE
),
168 virtual ExitCode
Entry()
172 //wxPrintf(wxT("%s: Thread #%d (%ld) starting to wait for semaphore...\n"),
173 // wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
177 //wxPrintf(wxT("%s: Thread #%d (%ld) acquired the semaphore.\n"),
178 // wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
182 //wxPrintf(wxT("%s: Thread #%d (%ld) releasing the semaphore.\n"),
183 // wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
195 WX_DEFINE_ARRAY_PTR(wxThread
*, ArrayThreads
);
197 // ----------------------------------------------------------------------------
199 // ----------------------------------------------------------------------------
201 class MiscThreadTestCase
: public CppUnit::TestCase
204 MiscThreadTestCase();
207 CPPUNIT_TEST_SUITE( MiscThreadTestCase
);
208 CPPUNIT_TEST( TestJoinable
);
209 CPPUNIT_TEST( TestDetached
);
210 CPPUNIT_TEST( TestThreadSuspend
);
211 CPPUNIT_TEST( TestThreadDelete
);
212 CPPUNIT_TEST( TestThreadRun
);
213 CPPUNIT_TEST( TestThreadConditions
);
214 CPPUNIT_TEST( TestSemaphore
);
215 CPPUNIT_TEST_SUITE_END();
219 void TestSemaphore();
221 void TestThreadSuspend();
222 void TestThreadDelete();
223 void TestThreadRun();
224 void TestThreadConditions();
226 DECLARE_NO_COPY_CLASS(MiscThreadTestCase
)
229 // register in the unnamed registry so that these tests are run by default
230 CPPUNIT_TEST_SUITE_REGISTRATION( MiscThreadTestCase
);
232 // also include in its own registry so that these tests can be run alone
233 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MiscThreadTestCase
, "MiscThreadTestCase" );
235 MiscThreadTestCase::MiscThreadTestCase()
237 int nCPUs
= wxThread::GetCPUCount();
239 wxThread::SetConcurrency(nCPUs
);
242 void MiscThreadTestCase::TestJoinable()
244 // calc 10! in the background
245 MyJoinableThread
thread(10);
246 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread
.Run() );
247 CPPUNIT_ASSERT_EQUAL( 362880, (unsigned long)thread
.Wait() );
250 void MiscThreadTestCase::TestDetached()
252 static const size_t nThreads
= 3;
253 MyDetachedThread
*threads
[nThreads
];
256 for ( n
= 0; n
< nThreads
; n
++ )
258 threads
[n
] = new MyDetachedThread(10, 'A' + n
);
261 threads
[0]->SetPriority(wxPRIORITY_MIN
);
262 threads
[1]->SetPriority(wxPRIORITY_MAX
);
264 for ( n
= 0; n
< nThreads
; n
++ )
266 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, threads
[n
]->Run() );
269 // wait until all threads terminate
270 CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR
, gs_cond
.Wait() );
273 void MiscThreadTestCase::TestSemaphore()
275 static const int SEM_LIMIT
= 3;
277 wxSemaphore
sem(SEM_LIMIT
, SEM_LIMIT
);
278 ArrayThreads threads
;
280 for ( int i
= 0; i
< 3*SEM_LIMIT
; i
++ )
282 threads
.Add(new MySemaphoreThread(i
, &sem
));
283 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, threads
.Last()->Run() );
286 for ( size_t n
= 0; n
< threads
.GetCount(); n
++ )
288 CPPUNIT_ASSERT_EQUAL( 0, (long)threads
[n
]->Wait() );
293 void MiscThreadTestCase::TestThreadSuspend()
295 MyDetachedThread
*thread
= new MyDetachedThread(15, 'X');
297 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread
->Run() );
299 // this is for this demo only, in a real life program we'd use another
300 // condition variable which would be signaled from wxThread::Entry() to
301 // tell us that the thread really started running - but here just wait a
302 // bit and hope that it will be enough (the problem is, of course, that
303 // the thread might still not run when we call Pause() which will result
307 for ( size_t n
= 0; n
< 3; n
++ )
313 // don't sleep but resume immediately the first time
317 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread
->Resume() );
320 // wait until the thread terminates
321 CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR
, gs_cond
.Wait() );
324 void MiscThreadTestCase::TestThreadDelete()
327 // As above, using Sleep() is only for testing here - we must use some
328 // synchronisation object instead to ensure that the thread is still
329 // running when we delete it - deleting a detached thread which already
330 // terminated will lead to a crash!
332 MyDetachedThread
*thread0
= new MyDetachedThread(30, 'W');
333 CPPUNIT_ASSERT_EQUAL( wxTHREAD_MISC_ERROR
, thread0
->Delete() );
334 // delete a thread which didn't start to run yet.
336 MyDetachedThread
*thread1
= new MyDetachedThread(30, 'Y');
337 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread1
->Run() );
339 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread1
->Delete() );
340 // delete a running thread
342 MyDetachedThread
*thread2
= new MyDetachedThread(30, 'Z');
343 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread2
->Run() );
345 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread2
->Pause() );
346 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread2
->Delete() );
347 // delete a sleeping thread
349 MyJoinableThread
thread3(20);
350 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread3
.Run() );
351 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread3
.Delete() );
352 // delete a joinable running thread
354 MyJoinableThread
thread4(2);
355 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread4
.Run() );
357 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread4
.Delete() );
358 // delete a joinable thread which already terminated
361 void MiscThreadTestCase::TestThreadRun()
363 MyJoinableThread
thread1(2);
364 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, thread1
.Run() );
365 thread1
.Wait(); // wait until the thread ends
367 // verify that running twice the same thread fails
368 WX_ASSERT_FAILS_WITH_ASSERT( thread1
.Run() );
371 void MiscThreadTestCase::TestThreadConditions()
374 wxCondition
condition(mutex
);
376 // otherwise its difficult to understand which log messages pertain to
378 //wxLogTrace(wxT("thread"), wxT("Local condition var is %08x, gs_cond = %08x"),
379 // condition.GetId(), gs_cond.GetId());
381 // create and launch threads
382 MyWaitingThread
*threads
[10];
385 for ( n
= 0; n
< WXSIZEOF(threads
); n
++ )
387 threads
[n
] = new MyWaitingThread( &mutex
, &condition
);
390 for ( n
= 0; n
< WXSIZEOF(threads
); n
++ )
392 CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR
, threads
[n
]->Run() );
395 // wait until all threads run
396 // NOTE: main thread is waiting for the other threads to start
398 while ( nRunning
< WXSIZEOF(threads
) )
400 CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR
, gs_cond
.Wait() );
404 // note that main thread is already running
410 // now wake one of them up
411 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR
, condition
.Signal() );
416 // wake all the (remaining) threads up, so that they can exit
417 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR
, condition
.Broadcast() );
419 // give them time to terminate (dirty!)