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:
Francesco Montorsi
2010-05-10 21:48:24 +00:00
parent 0fe260084e
commit 1f5496a0f5
12 changed files with 459 additions and 442 deletions

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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) $<

View File

@@ -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

View File

@@ -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) $<

View File

@@ -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

View File

@@ -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

View 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>

View 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"
> >

View File

@@ -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
View 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);
}