move code testing wxThread classes from the console sample to a new CppUnit test
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64283 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -132,7 +132,6 @@
|
|||||||
#define TEST_STDPATHS
|
#define TEST_STDPATHS
|
||||||
#define TEST_STREAMS
|
#define TEST_STREAMS
|
||||||
#define TEST_TEXTSTREAM
|
#define TEST_TEXTSTREAM
|
||||||
#define TEST_THREADS
|
|
||||||
#define TEST_TIMER
|
#define TEST_TIMER
|
||||||
// #define TEST_VOLUME --FIXME! (RN)
|
// #define TEST_VOLUME --FIXME! (RN)
|
||||||
#define TEST_WCHAR
|
#define TEST_WCHAR
|
||||||
@@ -3486,403 +3485,6 @@ static void TestTextInputStream()
|
|||||||
|
|
||||||
#endif // TEST_TEXTSTREAM
|
#endif // TEST_TEXTSTREAM
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// threads
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifdef TEST_THREADS
|
|
||||||
|
|
||||||
#include "wx/thread.h"
|
|
||||||
|
|
||||||
static size_t gs_counter = (size_t)-1;
|
|
||||||
static wxCriticalSection gs_critsect;
|
|
||||||
static wxSemaphore gs_cond;
|
|
||||||
|
|
||||||
class MyJoinableThread : public wxThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE)
|
|
||||||
{ m_n = n; Create(); }
|
|
||||||
|
|
||||||
// thread execution starts here
|
|
||||||
virtual ExitCode Entry();
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_n;
|
|
||||||
};
|
|
||||||
|
|
||||||
wxThread::ExitCode MyJoinableThread::Entry()
|
|
||||||
{
|
|
||||||
unsigned long res = 1;
|
|
||||||
for ( size_t n = 1; n < m_n; n++ )
|
|
||||||
{
|
|
||||||
res *= n;
|
|
||||||
|
|
||||||
// it's a loooong calculation :-)
|
|
||||||
Sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ExitCode)res;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyDetachedThread : public wxThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MyDetachedThread(size_t n, wxChar ch)
|
|
||||||
{
|
|
||||||
m_n = n;
|
|
||||||
m_ch = ch;
|
|
||||||
m_cancelled = false;
|
|
||||||
|
|
||||||
Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
// thread execution starts here
|
|
||||||
virtual ExitCode Entry();
|
|
||||||
|
|
||||||
// and stops here
|
|
||||||
virtual void OnExit();
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_n; // number of characters to write
|
|
||||||
wxChar m_ch; // character to write
|
|
||||||
|
|
||||||
bool m_cancelled; // false if we exit normally
|
|
||||||
};
|
|
||||||
|
|
||||||
wxThread::ExitCode MyDetachedThread::Entry()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
wxCriticalSectionLocker lock(gs_critsect);
|
|
||||||
if ( gs_counter == (size_t)-1 )
|
|
||||||
gs_counter = 1;
|
|
||||||
else
|
|
||||||
gs_counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( size_t n = 0; n < m_n; n++ )
|
|
||||||
{
|
|
||||||
if ( TestDestroy() )
|
|
||||||
{
|
|
||||||
m_cancelled = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxPutchar(m_ch);
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
wxThread::Sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyDetachedThread::OnExit()
|
|
||||||
{
|
|
||||||
wxLogTrace(wxT("thread"), wxT("Thread %ld is in OnExit"), GetId());
|
|
||||||
|
|
||||||
wxCriticalSectionLocker lock(gs_critsect);
|
|
||||||
if ( !--gs_counter && !m_cancelled )
|
|
||||||
gs_cond.Post();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TestDetachedThreads()
|
|
||||||
{
|
|
||||||
wxPuts(wxT("\n*** Testing detached threads ***"));
|
|
||||||
|
|
||||||
static const size_t nThreads = 3;
|
|
||||||
MyDetachedThread *threads[nThreads];
|
|
||||||
size_t n;
|
|
||||||
for ( n = 0; n < nThreads; n++ )
|
|
||||||
{
|
|
||||||
threads[n] = new MyDetachedThread(10, 'A' + n);
|
|
||||||
}
|
|
||||||
|
|
||||||
threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
|
|
||||||
threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
|
|
||||||
|
|
||||||
for ( n = 0; n < nThreads; n++ )
|
|
||||||
{
|
|
||||||
threads[n]->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until all threads terminate
|
|
||||||
gs_cond.Wait();
|
|
||||||
|
|
||||||
wxPuts(wxEmptyString);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TestJoinableThreads()
|
|
||||||
{
|
|
||||||
wxPuts(wxT("\n*** Testing a joinable thread (a loooong calculation...) ***"));
|
|
||||||
|
|
||||||
// calc 10! in the background
|
|
||||||
MyJoinableThread thread(10);
|
|
||||||
thread.Run();
|
|
||||||
|
|
||||||
wxPrintf(wxT("\nThread terminated with exit code %lu.\n"),
|
|
||||||
(unsigned long)thread.Wait());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TestThreadSuspend()
|
|
||||||
{
|
|
||||||
wxPuts(wxT("\n*** Testing thread suspend/resume functions ***"));
|
|
||||||
|
|
||||||
MyDetachedThread *thread = new MyDetachedThread(15, 'X');
|
|
||||||
|
|
||||||
thread->Run();
|
|
||||||
|
|
||||||
// this is for this demo only, in a real life program we'd use another
|
|
||||||
// condition variable which would be signaled from wxThread::Entry() to
|
|
||||||
// tell us that the thread really started running - but here just wait a
|
|
||||||
// bit and hope that it will be enough (the problem is, of course, that
|
|
||||||
// the thread might still not run when we call Pause() which will result
|
|
||||||
// in an error)
|
|
||||||
wxThread::Sleep(300);
|
|
||||||
|
|
||||||
for ( size_t n = 0; n < 3; n++ )
|
|
||||||
{
|
|
||||||
thread->Pause();
|
|
||||||
|
|
||||||
wxPuts(wxT("\nThread suspended"));
|
|
||||||
if ( n > 0 )
|
|
||||||
{
|
|
||||||
// don't sleep but resume immediately the first time
|
|
||||||
wxThread::Sleep(300);
|
|
||||||
}
|
|
||||||
wxPuts(wxT("Going to resume the thread"));
|
|
||||||
|
|
||||||
thread->Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
wxPuts(wxT("Waiting until it terminates now"));
|
|
||||||
|
|
||||||
// wait until the thread terminates
|
|
||||||
gs_cond.Wait();
|
|
||||||
|
|
||||||
wxPuts(wxEmptyString);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TestThreadDelete()
|
|
||||||
{
|
|
||||||
// As above, using Sleep() is only for testing here - we must use some
|
|
||||||
// synchronisation object instead to ensure that the thread is still
|
|
||||||
// running when we delete it - deleting a detached thread which already
|
|
||||||
// terminated will lead to a crash!
|
|
||||||
|
|
||||||
wxPuts(wxT("\n*** Testing thread delete function ***"));
|
|
||||||
|
|
||||||
MyDetachedThread *thread0 = new MyDetachedThread(30, 'W');
|
|
||||||
|
|
||||||
thread0->Delete();
|
|
||||||
|
|
||||||
wxPuts(wxT("\nDeleted a thread which didn't start to run yet."));
|
|
||||||
|
|
||||||
MyDetachedThread *thread1 = new MyDetachedThread(30, 'Y');
|
|
||||||
|
|
||||||
thread1->Run();
|
|
||||||
|
|
||||||
wxThread::Sleep(300);
|
|
||||||
|
|
||||||
thread1->Delete();
|
|
||||||
|
|
||||||
wxPuts(wxT("\nDeleted a running thread."));
|
|
||||||
|
|
||||||
MyDetachedThread *thread2 = new MyDetachedThread(30, 'Z');
|
|
||||||
|
|
||||||
thread2->Run();
|
|
||||||
|
|
||||||
wxThread::Sleep(300);
|
|
||||||
|
|
||||||
thread2->Pause();
|
|
||||||
|
|
||||||
thread2->Delete();
|
|
||||||
|
|
||||||
wxPuts(wxT("\nDeleted a sleeping thread."));
|
|
||||||
|
|
||||||
MyJoinableThread thread3(20);
|
|
||||||
thread3.Run();
|
|
||||||
|
|
||||||
thread3.Delete();
|
|
||||||
|
|
||||||
wxPuts(wxT("\nDeleted a joinable thread."));
|
|
||||||
|
|
||||||
MyJoinableThread thread4(2);
|
|
||||||
thread4.Run();
|
|
||||||
|
|
||||||
wxThread::Sleep(300);
|
|
||||||
|
|
||||||
thread4.Delete();
|
|
||||||
|
|
||||||
wxPuts(wxT("\nDeleted a joinable thread which already terminated."));
|
|
||||||
|
|
||||||
wxPuts(wxEmptyString);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyWaitingThread : public wxThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MyWaitingThread( wxMutex *mutex, wxCondition *condition )
|
|
||||||
{
|
|
||||||
m_mutex = mutex;
|
|
||||||
m_condition = condition;
|
|
||||||
|
|
||||||
Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ExitCode Entry()
|
|
||||||
{
|
|
||||||
wxPrintf(wxT("Thread %lu has started running.\n"), GetId());
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
gs_cond.Post();
|
|
||||||
|
|
||||||
wxPrintf(wxT("Thread %lu starts to wait...\n"), GetId());
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
m_mutex->Lock();
|
|
||||||
m_condition->Wait();
|
|
||||||
m_mutex->Unlock();
|
|
||||||
|
|
||||||
wxPrintf(wxT("Thread %lu finished to wait, exiting.\n"), GetId());
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
wxMutex *m_mutex;
|
|
||||||
wxCondition *m_condition;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void TestThreadConditions()
|
|
||||||
{
|
|
||||||
wxMutex mutex;
|
|
||||||
wxCondition condition(mutex);
|
|
||||||
|
|
||||||
// otherwise its difficult to understand which log messages pertain to
|
|
||||||
// which condition
|
|
||||||
//wxLogTrace(wxT("thread"), wxT("Local condition var is %08x, gs_cond = %08x"),
|
|
||||||
// condition.GetId(), gs_cond.GetId());
|
|
||||||
|
|
||||||
// create and launch threads
|
|
||||||
MyWaitingThread *threads[10];
|
|
||||||
|
|
||||||
size_t n;
|
|
||||||
for ( n = 0; n < WXSIZEOF(threads); n++ )
|
|
||||||
{
|
|
||||||
threads[n] = new MyWaitingThread( &mutex, &condition );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( n = 0; n < WXSIZEOF(threads); n++ )
|
|
||||||
{
|
|
||||||
threads[n]->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until all threads run
|
|
||||||
wxPuts(wxT("Main thread is waiting for the other threads to start"));
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
size_t nRunning = 0;
|
|
||||||
while ( nRunning < WXSIZEOF(threads) )
|
|
||||||
{
|
|
||||||
gs_cond.Wait();
|
|
||||||
|
|
||||||
nRunning++;
|
|
||||||
|
|
||||||
wxPrintf(wxT("Main thread: %u already running\n"), nRunning);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
wxPuts(wxT("Main thread: all threads started up."));
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
wxThread::Sleep(500);
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// now wake one of them up
|
|
||||||
wxPrintf(wxT("Main thread: about to signal the condition.\n"));
|
|
||||||
fflush(stdout);
|
|
||||||
condition.Signal();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wxThread::Sleep(200);
|
|
||||||
|
|
||||||
// wake all the (remaining) threads up, so that they can exit
|
|
||||||
wxPrintf(wxT("Main thread: about to broadcast the condition.\n"));
|
|
||||||
fflush(stdout);
|
|
||||||
condition.Broadcast();
|
|
||||||
|
|
||||||
// give them time to terminate (dirty!)
|
|
||||||
wxThread::Sleep(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// semaphore tests
|
|
||||||
#include "wx/datetime.h"
|
|
||||||
|
|
||||||
class MySemaphoreThread : public wxThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MySemaphoreThread(int i, wxSemaphore *sem)
|
|
||||||
: wxThread(wxTHREAD_JOINABLE),
|
|
||||||
m_sem(sem),
|
|
||||||
m_i(i)
|
|
||||||
{
|
|
||||||
Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ExitCode Entry()
|
|
||||||
{
|
|
||||||
wxPrintf(wxT("%s: Thread #%d (%ld) starting to wait for semaphore...\n"),
|
|
||||||
wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
|
||||||
|
|
||||||
m_sem->Wait();
|
|
||||||
|
|
||||||
wxPrintf(wxT("%s: Thread #%d (%ld) acquired the semaphore.\n"),
|
|
||||||
wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
|
||||||
|
|
||||||
Sleep(1000);
|
|
||||||
|
|
||||||
wxPrintf(wxT("%s: Thread #%d (%ld) releasing the semaphore.\n"),
|
|
||||||
wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
|
||||||
|
|
||||||
m_sem->Post();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
wxSemaphore *m_sem;
|
|
||||||
int m_i;
|
|
||||||
};
|
|
||||||
|
|
||||||
WX_DEFINE_ARRAY_PTR(wxThread *, ArrayThreads);
|
|
||||||
|
|
||||||
static void TestSemaphore()
|
|
||||||
{
|
|
||||||
wxPuts(wxT("*** Testing wxSemaphore class. ***"));
|
|
||||||
|
|
||||||
static const int SEM_LIMIT = 3;
|
|
||||||
|
|
||||||
wxSemaphore sem(SEM_LIMIT, SEM_LIMIT);
|
|
||||||
ArrayThreads threads;
|
|
||||||
|
|
||||||
for ( int i = 0; i < 3*SEM_LIMIT; i++ )
|
|
||||||
{
|
|
||||||
threads.Add(new MySemaphoreThread(i, &sem));
|
|
||||||
threads.Last()->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( size_t n = 0; n < threads.GetCount(); n++ )
|
|
||||||
{
|
|
||||||
threads[n]->Wait();
|
|
||||||
delete threads[n];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // TEST_THREADS
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// entry point
|
// entry point
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -4150,24 +3752,6 @@ int main(int argc, char **argv)
|
|||||||
TestTextInputStream();
|
TestTextInputStream();
|
||||||
#endif // TEST_TEXTSTREAM
|
#endif // TEST_TEXTSTREAM
|
||||||
|
|
||||||
#ifdef TEST_THREADS
|
|
||||||
int nCPUs = wxThread::GetCPUCount();
|
|
||||||
wxPrintf(wxT("This system has %d CPUs\n"), nCPUs);
|
|
||||||
if ( nCPUs != -1 )
|
|
||||||
wxThread::SetConcurrency(nCPUs);
|
|
||||||
|
|
||||||
TestJoinableThreads();
|
|
||||||
|
|
||||||
#if TEST_ALL
|
|
||||||
TestJoinableThreads();
|
|
||||||
TestDetachedThreads();
|
|
||||||
TestThreadSuspend();
|
|
||||||
TestThreadDelete();
|
|
||||||
TestThreadConditions();
|
|
||||||
TestSemaphore();
|
|
||||||
#endif
|
|
||||||
#endif // TEST_THREADS
|
|
||||||
|
|
||||||
#ifdef TEST_TIMER
|
#ifdef TEST_TIMER
|
||||||
TestStopWatch();
|
TestStopWatch();
|
||||||
TestTimer();
|
TestTimer();
|
||||||
|
@@ -113,6 +113,7 @@ TEST_OBJECTS = \
|
|||||||
test_zlibstream.o \
|
test_zlibstream.o \
|
||||||
test_textfiletest.o \
|
test_textfiletest.o \
|
||||||
test_atomic.o \
|
test_atomic.o \
|
||||||
|
test_misc.o \
|
||||||
test_queue.o \
|
test_queue.o \
|
||||||
test_tls.o \
|
test_tls.o \
|
||||||
test_uris.o \
|
test_uris.o \
|
||||||
@@ -532,6 +533,9 @@ test_textfiletest.o: $(srcdir)/textfile/textfiletest.cpp $(TEST_ODEP)
|
|||||||
test_atomic.o: $(srcdir)/thread/atomic.cpp $(TEST_ODEP)
|
test_atomic.o: $(srcdir)/thread/atomic.cpp $(TEST_ODEP)
|
||||||
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/thread/atomic.cpp
|
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/thread/atomic.cpp
|
||||||
|
|
||||||
|
test_misc.o: $(srcdir)/thread/misc.cpp $(TEST_ODEP)
|
||||||
|
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/thread/misc.cpp
|
||||||
|
|
||||||
test_queue.o: $(srcdir)/thread/queue.cpp $(TEST_ODEP)
|
test_queue.o: $(srcdir)/thread/queue.cpp $(TEST_ODEP)
|
||||||
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/thread/queue.cpp
|
$(CXXC) -c -o $@ $(TEST_CXXFLAGS) $(srcdir)/thread/queue.cpp
|
||||||
|
|
||||||
|
@@ -97,6 +97,7 @@ TEST_OBJECTS = \
|
|||||||
$(OBJS)\test_zlibstream.obj \
|
$(OBJS)\test_zlibstream.obj \
|
||||||
$(OBJS)\test_textfiletest.obj \
|
$(OBJS)\test_textfiletest.obj \
|
||||||
$(OBJS)\test_atomic.obj \
|
$(OBJS)\test_atomic.obj \
|
||||||
|
$(OBJS)\test_misc.obj \
|
||||||
$(OBJS)\test_queue.obj \
|
$(OBJS)\test_queue.obj \
|
||||||
$(OBJS)\test_tls.obj \
|
$(OBJS)\test_tls.obj \
|
||||||
$(OBJS)\test_uris.obj \
|
$(OBJS)\test_uris.obj \
|
||||||
@@ -574,6 +575,9 @@ $(OBJS)\test_textfiletest.obj: .\textfile\textfiletest.cpp
|
|||||||
$(OBJS)\test_atomic.obj: .\thread\atomic.cpp
|
$(OBJS)\test_atomic.obj: .\thread\atomic.cpp
|
||||||
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\thread\atomic.cpp
|
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\thread\atomic.cpp
|
||||||
|
|
||||||
|
$(OBJS)\test_misc.obj: .\thread\misc.cpp
|
||||||
|
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\thread\misc.cpp
|
||||||
|
|
||||||
$(OBJS)\test_queue.obj: .\thread\queue.cpp
|
$(OBJS)\test_queue.obj: .\thread\queue.cpp
|
||||||
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\thread\queue.cpp
|
$(CXX) -q -c -P -o$@ $(TEST_CXXFLAGS) .\thread\queue.cpp
|
||||||
|
|
||||||
|
@@ -89,6 +89,7 @@ TEST_OBJECTS = \
|
|||||||
$(OBJS)\test_zlibstream.o \
|
$(OBJS)\test_zlibstream.o \
|
||||||
$(OBJS)\test_textfiletest.o \
|
$(OBJS)\test_textfiletest.o \
|
||||||
$(OBJS)\test_atomic.o \
|
$(OBJS)\test_atomic.o \
|
||||||
|
$(OBJS)\test_misc.o \
|
||||||
$(OBJS)\test_queue.o \
|
$(OBJS)\test_queue.o \
|
||||||
$(OBJS)\test_tls.o \
|
$(OBJS)\test_tls.o \
|
||||||
$(OBJS)\test_uris.o \
|
$(OBJS)\test_uris.o \
|
||||||
@@ -555,6 +556,9 @@ $(OBJS)\test_textfiletest.o: ./textfile/textfiletest.cpp
|
|||||||
$(OBJS)\test_atomic.o: ./thread/atomic.cpp
|
$(OBJS)\test_atomic.o: ./thread/atomic.cpp
|
||||||
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
||||||
|
|
||||||
|
$(OBJS)\test_misc.o: ./thread/misc.cpp
|
||||||
|
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
||||||
|
|
||||||
$(OBJS)\test_queue.o: ./thread/queue.cpp
|
$(OBJS)\test_queue.o: ./thread/queue.cpp
|
||||||
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
$(CXX) -c -o $@ $(TEST_CXXFLAGS) $(CPPDEPS) $<
|
||||||
|
|
||||||
|
@@ -91,6 +91,7 @@ TEST_OBJECTS = \
|
|||||||
$(OBJS)\test_zlibstream.obj \
|
$(OBJS)\test_zlibstream.obj \
|
||||||
$(OBJS)\test_textfiletest.obj \
|
$(OBJS)\test_textfiletest.obj \
|
||||||
$(OBJS)\test_atomic.obj \
|
$(OBJS)\test_atomic.obj \
|
||||||
|
$(OBJS)\test_misc.obj \
|
||||||
$(OBJS)\test_queue.obj \
|
$(OBJS)\test_queue.obj \
|
||||||
$(OBJS)\test_tls.obj \
|
$(OBJS)\test_tls.obj \
|
||||||
$(OBJS)\test_uris.obj \
|
$(OBJS)\test_uris.obj \
|
||||||
@@ -700,6 +701,9 @@ $(OBJS)\test_textfiletest.obj: .\textfile\textfiletest.cpp
|
|||||||
$(OBJS)\test_atomic.obj: .\thread\atomic.cpp
|
$(OBJS)\test_atomic.obj: .\thread\atomic.cpp
|
||||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\thread\atomic.cpp
|
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\thread\atomic.cpp
|
||||||
|
|
||||||
|
$(OBJS)\test_misc.obj: .\thread\misc.cpp
|
||||||
|
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\thread\misc.cpp
|
||||||
|
|
||||||
$(OBJS)\test_queue.obj: .\thread\queue.cpp
|
$(OBJS)\test_queue.obj: .\thread\queue.cpp
|
||||||
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\thread\queue.cpp
|
$(CXX) /c /nologo /TP /Fo$@ $(TEST_CXXFLAGS) .\thread\queue.cpp
|
||||||
|
|
||||||
|
@@ -327,6 +327,7 @@ TEST_OBJECTS = &
|
|||||||
$(OBJS)\test_zlibstream.obj &
|
$(OBJS)\test_zlibstream.obj &
|
||||||
$(OBJS)\test_textfiletest.obj &
|
$(OBJS)\test_textfiletest.obj &
|
||||||
$(OBJS)\test_atomic.obj &
|
$(OBJS)\test_atomic.obj &
|
||||||
|
$(OBJS)\test_misc.obj &
|
||||||
$(OBJS)\test_queue.obj &
|
$(OBJS)\test_queue.obj &
|
||||||
$(OBJS)\test_tls.obj &
|
$(OBJS)\test_tls.obj &
|
||||||
$(OBJS)\test_uris.obj &
|
$(OBJS)\test_uris.obj &
|
||||||
@@ -612,6 +613,9 @@ $(OBJS)\test_textfiletest.obj : .AUTODEPEND .\textfile\textfiletest.cpp
|
|||||||
$(OBJS)\test_atomic.obj : .AUTODEPEND .\thread\atomic.cpp
|
$(OBJS)\test_atomic.obj : .AUTODEPEND .\thread\atomic.cpp
|
||||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
||||||
|
|
||||||
|
$(OBJS)\test_misc.obj : .AUTODEPEND .\thread\misc.cpp
|
||||||
|
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
||||||
|
|
||||||
$(OBJS)\test_queue.obj : .AUTODEPEND .\thread\queue.cpp
|
$(OBJS)\test_queue.obj : .AUTODEPEND .\thread\queue.cpp
|
||||||
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_CXXFLAGS) $<
|
||||||
|
|
||||||
|
@@ -88,6 +88,7 @@
|
|||||||
streams/zlibstream.cpp
|
streams/zlibstream.cpp
|
||||||
textfile/textfiletest.cpp
|
textfile/textfiletest.cpp
|
||||||
thread/atomic.cpp
|
thread/atomic.cpp
|
||||||
|
thread/misc.cpp
|
||||||
thread/queue.cpp
|
thread/queue.cpp
|
||||||
thread/tls.cpp
|
thread/tls.cpp
|
||||||
uris/uris.cpp
|
uris/uris.cpp
|
||||||
|
@@ -389,6 +389,10 @@ SOURCE=.\streams\memstream.cpp
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\thread\misc.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\misc\misctests.cpp
|
SOURCE=.\misc\misctests.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@@ -727,6 +727,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\streams\memstream.cpp">
|
RelativePath=".\streams\memstream.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\thread\misc.cpp">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\misc\misctests.cpp">
|
RelativePath=".\misc\misctests.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
@@ -1043,6 +1043,10 @@
|
|||||||
RelativePath=".\streams\memstream.cpp"
|
RelativePath=".\streams\memstream.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\thread\misc.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\misc\misctests.cpp"
|
RelativePath=".\misc\misctests.cpp"
|
||||||
>
|
>
|
||||||
|
@@ -1,16 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
<!--
|
|
||||||
|
|
||||||
This project was generated by
|
|
||||||
Bakefile 0.2.8 (http://www.bakefile.org)
|
|
||||||
Do not modify, all changes will be overwritten!
|
|
||||||
|
|
||||||
-->
|
|
||||||
<VisualStudioProject
|
<VisualStudioProject
|
||||||
ProjectType="Visual C++"
|
ProjectType="Visual C++"
|
||||||
Version="9.00"
|
Version="9,00"
|
||||||
Name="test"
|
Name="test"
|
||||||
ProjectGUID="{2F45723C-ED6B-5F60-8BFF-6B3609464A7B}"
|
ProjectGUID="{2F45723C-ED6B-5F60-8BFF-6B3609464A7B}"
|
||||||
|
TargetFrameworkVersion="0"
|
||||||
>
|
>
|
||||||
<Platforms>
|
<Platforms>
|
||||||
<Platform
|
<Platform
|
||||||
@@ -18,7 +12,6 @@
|
|||||||
/>
|
/>
|
||||||
</Platforms>
|
</Platforms>
|
||||||
<ToolFiles>
|
<ToolFiles>
|
||||||
|
|
||||||
</ToolFiles>
|
</ToolFiles>
|
||||||
<Configurations>
|
<Configurations>
|
||||||
<Configuration
|
<Configuration
|
||||||
@@ -51,7 +44,7 @@
|
|||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
AdditionalOptions="/MP"
|
AdditionalOptions="/MP"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories=".\..\lib\vc_lib\mswud;.\..\include;."
|
AdditionalIncludeDirectories=".\..\lib\vc_lib\mswud;.\..\include;.;F:\cppunit\include"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;__WXMSW__;_UNICODE;_CONSOLE;wxUSE_GUI=0"
|
PreprocessorDefinitions="WIN32;_DEBUG;__WXMSW__;_UNICODE;_CONSOLE;wxUSE_GUI=0"
|
||||||
ExceptionHandling="1"
|
ExceptionHandling="1"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
@@ -86,7 +79,7 @@
|
|||||||
OutputFile="vc_mswud\test.exe"
|
OutputFile="vc_mswud\test.exe"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
AdditionalLibraryDirectories=".\..\lib\vc_lib"
|
AdditionalLibraryDirectories=".\..\lib\vc_lib;F:\cppunit\lib"
|
||||||
GenerateManifest="true"
|
GenerateManifest="true"
|
||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
ProgramDatabaseFile="vc_mswud\test.pdb"
|
ProgramDatabaseFile="vc_mswud\test.pdb"
|
||||||
@@ -104,8 +97,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswud\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswud\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -185,9 +178,9 @@
|
|||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
ProgramDatabaseFile="vc_mswu\test.pdb"
|
ProgramDatabaseFile="vc_mswu\test.pdb"
|
||||||
SubSystem="1"
|
SubSystem="1"
|
||||||
TargetMachine="1"
|
|
||||||
OptimizeReferences="2"
|
OptimizeReferences="2"
|
||||||
EnableCOMDATFolding="2"
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCALinkTool"
|
Name="VCALinkTool"
|
||||||
@@ -200,8 +193,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswu\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswu\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -296,8 +289,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswunivud\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswunivud\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -377,9 +370,9 @@
|
|||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
ProgramDatabaseFile="vc_mswunivu\test.pdb"
|
ProgramDatabaseFile="vc_mswunivu\test.pdb"
|
||||||
SubSystem="1"
|
SubSystem="1"
|
||||||
TargetMachine="1"
|
|
||||||
OptimizeReferences="2"
|
OptimizeReferences="2"
|
||||||
EnableCOMDATFolding="2"
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCALinkTool"
|
Name="VCALinkTool"
|
||||||
@@ -392,8 +385,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswunivu\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswunivu\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -488,8 +481,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswuddll\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswuddll\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -569,9 +562,9 @@
|
|||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
ProgramDatabaseFile="vc_mswudll\test.pdb"
|
ProgramDatabaseFile="vc_mswudll\test.pdb"
|
||||||
SubSystem="1"
|
SubSystem="1"
|
||||||
TargetMachine="1"
|
|
||||||
OptimizeReferences="2"
|
OptimizeReferences="2"
|
||||||
EnableCOMDATFolding="2"
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCALinkTool"
|
Name="VCALinkTool"
|
||||||
@@ -584,8 +577,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswudll\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswudll\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -680,8 +673,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswunivuddll\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswunivuddll\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -761,9 +754,9 @@
|
|||||||
GenerateDebugInformation="true"
|
GenerateDebugInformation="true"
|
||||||
ProgramDatabaseFile="vc_mswunivudll\test.pdb"
|
ProgramDatabaseFile="vc_mswunivudll\test.pdb"
|
||||||
SubSystem="1"
|
SubSystem="1"
|
||||||
TargetMachine="1"
|
|
||||||
OptimizeReferences="2"
|
OptimizeReferences="2"
|
||||||
EnableCOMDATFolding="2"
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCALinkTool"
|
Name="VCALinkTool"
|
||||||
@@ -776,8 +769,8 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCBscMakeTool"
|
Name="VCBscMakeTool"
|
||||||
OutputFile="vc_mswunivudll\test_vc9_test.bsc"
|
|
||||||
SuppressStartupBanner="true"
|
SuppressStartupBanner="true"
|
||||||
|
OutputFile="vc_mswunivudll\test_vc9_test.bsc"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCFxCopTool"
|
Name="VCFxCopTool"
|
||||||
@@ -791,7 +784,6 @@
|
|||||||
</Configuration>
|
</Configuration>
|
||||||
</Configurations>
|
</Configurations>
|
||||||
<References>
|
<References>
|
||||||
|
|
||||||
</References>
|
</References>
|
||||||
<Files>
|
<Files>
|
||||||
<Filter
|
<Filter
|
||||||
@@ -1015,6 +1007,10 @@
|
|||||||
RelativePath=".\streams\memstream.cpp"
|
RelativePath=".\streams\memstream.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\thread\misc.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\misc\misctests.cpp"
|
RelativePath=".\misc\misctests.cpp"
|
||||||
>
|
>
|
||||||
@@ -1146,7 +1142,5 @@
|
|||||||
</Filter>
|
</Filter>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
|
|
||||||
</Globals>
|
</Globals>
|
||||||
</VisualStudioProject>
|
</VisualStudioProject>
|
||||||
|
|
||||||
|
407
tests/thread/misc.cpp
Normal file
407
tests/thread/misc.cpp
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: tests/thread/misc.cpp
|
||||||
|
// Purpose: Miscellaneous wxThread test cases
|
||||||
|
// Author: Francesco Montorsi (extracted from console sample)
|
||||||
|
// Created: 2010-05-10
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) 2010 wxWidgets team
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// headers
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "testprec.h"
|
||||||
|
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma hdrstop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WX_PRECOMP
|
||||||
|
#endif // WX_PRECOMP
|
||||||
|
|
||||||
|
#include "wx/thread.h"
|
||||||
|
#include "wx/tls.h"
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// globals
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static size_t gs_counter = (size_t)-1;
|
||||||
|
static wxCriticalSection gs_critsect;
|
||||||
|
static wxSemaphore gs_cond;
|
||||||
|
|
||||||
|
class MyJoinableThread : public wxThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyJoinableThread(size_t n) : wxThread(wxTHREAD_JOINABLE)
|
||||||
|
{ m_n = n; Create(); }
|
||||||
|
|
||||||
|
// thread execution starts here
|
||||||
|
virtual ExitCode Entry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
wxThread::ExitCode MyJoinableThread::Entry()
|
||||||
|
{
|
||||||
|
unsigned long res = 1;
|
||||||
|
for ( size_t n = 1; n < m_n; n++ )
|
||||||
|
{
|
||||||
|
res *= n;
|
||||||
|
|
||||||
|
// it's a loooong calculation :-)
|
||||||
|
wxMilliSleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ExitCode)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyDetachedThread : public wxThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyDetachedThread(size_t n, wxChar ch)
|
||||||
|
{
|
||||||
|
m_n = n;
|
||||||
|
m_ch = ch;
|
||||||
|
m_cancelled = false;
|
||||||
|
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// thread execution starts here
|
||||||
|
virtual ExitCode Entry();
|
||||||
|
|
||||||
|
// and stops here
|
||||||
|
virtual void OnExit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_n; // number of characters to write
|
||||||
|
wxChar m_ch; // character to write
|
||||||
|
|
||||||
|
bool m_cancelled; // false if we exit normally
|
||||||
|
};
|
||||||
|
|
||||||
|
wxThread::ExitCode MyDetachedThread::Entry()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker lock(gs_critsect);
|
||||||
|
if ( gs_counter == (size_t)-1 )
|
||||||
|
gs_counter = 1;
|
||||||
|
else
|
||||||
|
gs_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( size_t n = 0; n < m_n; n++ )
|
||||||
|
{
|
||||||
|
if ( TestDestroy() )
|
||||||
|
{
|
||||||
|
m_cancelled = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wxPutchar(m_ch);
|
||||||
|
//fflush(stdout);
|
||||||
|
|
||||||
|
wxThread::Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyDetachedThread::OnExit()
|
||||||
|
{
|
||||||
|
//wxLogTrace(wxT("thread"), wxT("Thread %ld is in OnExit"), GetId());
|
||||||
|
|
||||||
|
wxCriticalSectionLocker lock(gs_critsect);
|
||||||
|
if ( !--gs_counter && !m_cancelled )
|
||||||
|
gs_cond.Post();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyWaitingThread : public wxThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyWaitingThread( wxMutex *mutex, wxCondition *condition )
|
||||||
|
{
|
||||||
|
m_mutex = mutex;
|
||||||
|
m_condition = condition;
|
||||||
|
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ExitCode Entry()
|
||||||
|
{
|
||||||
|
//wxPrintf(wxT("Thread %lu has started running.\n"), GetId());
|
||||||
|
gs_cond.Post();
|
||||||
|
|
||||||
|
//wxPrintf(wxT("Thread %lu starts to wait...\n"), GetId());
|
||||||
|
|
||||||
|
m_mutex->Lock();
|
||||||
|
m_condition->Wait();
|
||||||
|
m_mutex->Unlock();
|
||||||
|
|
||||||
|
//wxPrintf(wxT("Thread %lu finished to wait, exiting.\n"), GetId());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxMutex *m_mutex;
|
||||||
|
wxCondition *m_condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
// semaphore tests
|
||||||
|
#include "wx/datetime.h"
|
||||||
|
|
||||||
|
class MySemaphoreThread : public wxThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MySemaphoreThread(int i, wxSemaphore *sem)
|
||||||
|
: wxThread(wxTHREAD_JOINABLE),
|
||||||
|
m_sem(sem),
|
||||||
|
m_i(i)
|
||||||
|
{
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ExitCode Entry()
|
||||||
|
{
|
||||||
|
//wxPrintf(wxT("%s: Thread #%d (%ld) starting to wait for semaphore...\n"),
|
||||||
|
// wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
||||||
|
|
||||||
|
m_sem->Wait();
|
||||||
|
|
||||||
|
//wxPrintf(wxT("%s: Thread #%d (%ld) acquired the semaphore.\n"),
|
||||||
|
// wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
||||||
|
|
||||||
|
Sleep(1000);
|
||||||
|
|
||||||
|
//wxPrintf(wxT("%s: Thread #%d (%ld) releasing the semaphore.\n"),
|
||||||
|
// wxDateTime::Now().FormatTime().c_str(), m_i, (long)GetId());
|
||||||
|
|
||||||
|
m_sem->Post();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxSemaphore *m_sem;
|
||||||
|
int m_i;
|
||||||
|
};
|
||||||
|
|
||||||
|
WX_DEFINE_ARRAY_PTR(wxThread *, ArrayThreads);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// test class
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class MiscThreadTestCase : public CppUnit::TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MiscThreadTestCase();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CPPUNIT_TEST_SUITE( MiscThreadTestCase );
|
||||||
|
CPPUNIT_TEST( TestJoinable );
|
||||||
|
CPPUNIT_TEST( TestDetached );
|
||||||
|
CPPUNIT_TEST( TestThreadSuspend );
|
||||||
|
CPPUNIT_TEST( TestThreadDelete );
|
||||||
|
CPPUNIT_TEST( TestThreadConditions );
|
||||||
|
CPPUNIT_TEST( TestSemaphore );
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
|
void TestJoinable();
|
||||||
|
void TestDetached();
|
||||||
|
void TestSemaphore();
|
||||||
|
|
||||||
|
void TestThreadSuspend();
|
||||||
|
void TestThreadDelete();
|
||||||
|
void TestThreadConditions();
|
||||||
|
|
||||||
|
DECLARE_NO_COPY_CLASS(MiscThreadTestCase)
|
||||||
|
};
|
||||||
|
|
||||||
|
// register in the unnamed registry so that these tests are run by default
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION( MiscThreadTestCase );
|
||||||
|
|
||||||
|
// also include in it's own registry so that these tests can be run alone
|
||||||
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MiscThreadTestCase, "MiscThreadTestCase" );
|
||||||
|
|
||||||
|
MiscThreadTestCase::MiscThreadTestCase()
|
||||||
|
{
|
||||||
|
int nCPUs = wxThread::GetCPUCount();
|
||||||
|
if ( nCPUs != -1 )
|
||||||
|
wxThread::SetConcurrency(nCPUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscThreadTestCase::TestJoinable()
|
||||||
|
{
|
||||||
|
// calc 10! in the background
|
||||||
|
MyJoinableThread thread(10);
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread.Run() );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 362880, (unsigned long)thread.Wait() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscThreadTestCase::TestDetached()
|
||||||
|
{
|
||||||
|
static const size_t nThreads = 3;
|
||||||
|
MyDetachedThread *threads[nThreads];
|
||||||
|
|
||||||
|
size_t n;
|
||||||
|
for ( n = 0; n < nThreads; n++ )
|
||||||
|
{
|
||||||
|
threads[n] = new MyDetachedThread(10, 'A' + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
|
||||||
|
threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
|
||||||
|
|
||||||
|
for ( n = 0; n < nThreads; n++ )
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until all threads terminate
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscThreadTestCase::TestSemaphore()
|
||||||
|
{
|
||||||
|
static const int SEM_LIMIT = 3;
|
||||||
|
|
||||||
|
wxSemaphore sem(SEM_LIMIT, SEM_LIMIT);
|
||||||
|
ArrayThreads threads;
|
||||||
|
|
||||||
|
for ( int i = 0; i < 3*SEM_LIMIT; i++ )
|
||||||
|
{
|
||||||
|
threads.Add(new MySemaphoreThread(i, &sem));
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads.Last()->Run() );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( size_t n = 0; n < threads.GetCount(); n++ )
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 0, (long)threads[n]->Wait() );
|
||||||
|
delete threads[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscThreadTestCase::TestThreadSuspend()
|
||||||
|
{
|
||||||
|
MyDetachedThread *thread = new MyDetachedThread(15, 'X');
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Run() );
|
||||||
|
|
||||||
|
// this is for this demo only, in a real life program we'd use another
|
||||||
|
// condition variable which would be signaled from wxThread::Entry() to
|
||||||
|
// tell us that the thread really started running - but here just wait a
|
||||||
|
// bit and hope that it will be enough (the problem is, of course, that
|
||||||
|
// the thread might still not run when we call Pause() which will result
|
||||||
|
// in an error)
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
|
||||||
|
for ( size_t n = 0; n < 3; n++ )
|
||||||
|
{
|
||||||
|
thread->Pause();
|
||||||
|
|
||||||
|
if ( n > 0 )
|
||||||
|
{
|
||||||
|
// don't sleep but resume immediately the first time
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Resume() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until the thread terminates
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscThreadTestCase::TestThreadDelete()
|
||||||
|
{
|
||||||
|
// As above, using Sleep() is only for testing here - we must use some
|
||||||
|
// synchronisation object instead to ensure that the thread is still
|
||||||
|
// running when we delete it - deleting a detached thread which already
|
||||||
|
// terminated will lead to a crash!
|
||||||
|
|
||||||
|
MyDetachedThread *thread0 = new MyDetachedThread(30, 'W');
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_MISC_ERROR, thread0->Delete() );
|
||||||
|
// delete a thread which didn't start to run yet.
|
||||||
|
|
||||||
|
MyDetachedThread *thread1 = new MyDetachedThread(30, 'Y');
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1->Run() );
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread1->Delete() );
|
||||||
|
// delete a running thread
|
||||||
|
|
||||||
|
MyDetachedThread *thread2 = new MyDetachedThread(30, 'Z');
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Run() );
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Pause() );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread2->Delete() );
|
||||||
|
// delete a sleeping thread
|
||||||
|
|
||||||
|
MyJoinableThread thread3(20);
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread3.Run() );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread3.Delete() );
|
||||||
|
// delete a joinable thread
|
||||||
|
|
||||||
|
MyJoinableThread thread4(2);
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread4.Run() );
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread4.Delete() );
|
||||||
|
// delete a joinable thread which already terminated
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiscThreadTestCase::TestThreadConditions()
|
||||||
|
{
|
||||||
|
wxMutex mutex;
|
||||||
|
wxCondition condition(mutex);
|
||||||
|
|
||||||
|
// otherwise its difficult to understand which log messages pertain to
|
||||||
|
// which condition
|
||||||
|
//wxLogTrace(wxT("thread"), wxT("Local condition var is %08x, gs_cond = %08x"),
|
||||||
|
// condition.GetId(), gs_cond.GetId());
|
||||||
|
|
||||||
|
// create and launch threads
|
||||||
|
MyWaitingThread *threads[10];
|
||||||
|
|
||||||
|
size_t n;
|
||||||
|
for ( n = 0; n < WXSIZEOF(threads); n++ )
|
||||||
|
{
|
||||||
|
threads[n] = new MyWaitingThread( &mutex, &condition );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( n = 0; n < WXSIZEOF(threads); n++ )
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until all threads run
|
||||||
|
// NOTE: main thread is waiting for the other threads to start
|
||||||
|
size_t nRunning = 0;
|
||||||
|
while ( nRunning < WXSIZEOF(threads) )
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() );
|
||||||
|
|
||||||
|
nRunning++;
|
||||||
|
|
||||||
|
// note that main thread is already running
|
||||||
|
}
|
||||||
|
|
||||||
|
wxThread::Sleep(500);
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// now wake one of them up
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Signal() );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wxThread::Sleep(200);
|
||||||
|
|
||||||
|
// wake all the (remaining) threads up, so that they can exit
|
||||||
|
CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Broadcast() );
|
||||||
|
|
||||||
|
// give them time to terminate (dirty!)
|
||||||
|
wxThread::Sleep(500);
|
||||||
|
}
|
Reference in New Issue
Block a user