2007-07-04 16:54:14 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Name: tests/thread/atomic.cpp
|
|
|
|
// Purpose: wxAtomic??? unit test
|
|
|
|
// Author: Armel Asselin
|
|
|
|
// Created: 2006-12-14
|
|
|
|
// RCS-ID: $Id$
|
|
|
|
// Copyright: (c) 2006 Armel Asselin
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// headers
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "testprec.h"
|
|
|
|
|
|
|
|
#ifdef __BORLANDC__
|
|
|
|
#pragma hdrstop
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef WX_PRECOMP
|
|
|
|
#endif // WX_PRECOMP
|
|
|
|
|
|
|
|
#include "wx/atomic.h"
|
|
|
|
#include "wx/thread.h"
|
|
|
|
#include "wx/dynarray.h"
|
2007-08-22 11:18:31 -04:00
|
|
|
#include "wx/log.h"
|
|
|
|
|
2007-07-04 16:54:14 -04:00
|
|
|
WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// test class
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class AtomicTestCase : public CppUnit::TestCase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AtomicTestCase() { }
|
|
|
|
|
|
|
|
enum ETestType
|
|
|
|
{
|
|
|
|
IncAndDecMixed,
|
|
|
|
IncOnly,
|
|
|
|
DecOnly
|
|
|
|
};
|
|
|
|
|
2008-01-12 20:13:03 -05:00
|
|
|
private:
|
2007-07-04 16:54:14 -04:00
|
|
|
class MyThread : public wxThread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MyThread(wxAtomicInt &operateOn, ETestType testType) : wxThread(wxTHREAD_JOINABLE),
|
|
|
|
m_operateOn(operateOn), m_testType(testType) {}
|
|
|
|
|
|
|
|
// thread execution starts here
|
|
|
|
virtual void *Entry();
|
|
|
|
|
|
|
|
public:
|
|
|
|
wxAtomicInt &m_operateOn;
|
|
|
|
ETestType m_testType;
|
|
|
|
};
|
|
|
|
|
|
|
|
CPPUNIT_TEST_SUITE( AtomicTestCase );
|
|
|
|
CPPUNIT_TEST( TestNoThread );
|
2007-09-10 18:12:39 -04:00
|
|
|
CPPUNIT_TEST( TestDecReturn );
|
2007-07-04 16:54:14 -04:00
|
|
|
CPPUNIT_TEST( TestTwoThreadsMix );
|
|
|
|
CPPUNIT_TEST( TestTenThreadsMix );
|
|
|
|
CPPUNIT_TEST( TestTwoThreadsSeparate );
|
|
|
|
CPPUNIT_TEST( TestTenThreadsSeparate );
|
|
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
|
|
|
|
void TestNoThread();
|
2007-09-10 18:12:39 -04:00
|
|
|
void TestDecReturn();
|
2007-07-04 16:54:14 -04:00
|
|
|
void TestTenThreadsMix() { TestWithThreads(10, IncAndDecMixed); }
|
|
|
|
void TestTwoThreadsMix() { TestWithThreads(2, IncAndDecMixed); }
|
|
|
|
void TestTenThreadsSeparate() { TestWithThreads(10, IncOnly); }
|
|
|
|
void TestTwoThreadsSeparate() { TestWithThreads(2, IncOnly); }
|
|
|
|
void TestWithThreads(int count, ETestType testtype);
|
|
|
|
|
|
|
|
DECLARE_NO_COPY_CLASS(AtomicTestCase)
|
|
|
|
};
|
|
|
|
|
|
|
|
// register in the unnamed registry so that these tests are run by default
|
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION( AtomicTestCase );
|
|
|
|
|
|
|
|
// also include in it's own registry so that these tests can be run alone
|
|
|
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( AtomicTestCase, "AtomicTestCase" );
|
|
|
|
|
|
|
|
void AtomicTestCase::TestNoThread()
|
|
|
|
{
|
|
|
|
wxAtomicInt int1=0, int2=0;
|
|
|
|
|
|
|
|
for (wxInt32 i=0; i<10000000; ++i)
|
|
|
|
{
|
|
|
|
wxAtomicInc(int1);
|
|
|
|
wxAtomicDec(int2);
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT( int1 == 10000000 );
|
|
|
|
CPPUNIT_ASSERT( int2 == -10000000 );
|
|
|
|
}
|
|
|
|
|
2007-09-10 18:12:39 -04:00
|
|
|
void AtomicTestCase::TestDecReturn()
|
|
|
|
{
|
|
|
|
wxAtomicInt i(0);
|
|
|
|
wxAtomicInc(i);
|
|
|
|
wxAtomicInc(i);
|
|
|
|
CPPUNIT_ASSERT( i == 2 );
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT( wxAtomicDec(i) > 0 );
|
|
|
|
CPPUNIT_ASSERT( wxAtomicDec(i) == 0 );
|
|
|
|
}
|
|
|
|
|
2007-07-04 16:54:14 -04:00
|
|
|
void AtomicTestCase::TestWithThreads(int count, ETestType testType)
|
|
|
|
{
|
|
|
|
wxAtomicInt int1=0;
|
|
|
|
|
|
|
|
wxArrayThread threads;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for ( i = 0; i < count; ++i )
|
|
|
|
{
|
|
|
|
ETestType actualThreadType;
|
|
|
|
switch(testType)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
actualThreadType = testType;
|
|
|
|
break;
|
|
|
|
case IncOnly:
|
|
|
|
actualThreadType = (i&1)==0 ? IncOnly : DecOnly;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
MyThread *thread = new MyThread(int1, actualThreadType);
|
|
|
|
|
|
|
|
if ( thread->Create() != wxTHREAD_NO_ERROR )
|
|
|
|
{
|
|
|
|
wxLogError(wxT("Can't create thread!"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
threads.Add(thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( i = 0; i < count; ++i )
|
|
|
|
{
|
|
|
|
threads[i]->Run();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for ( i = 0; i < count; ++i )
|
|
|
|
{
|
|
|
|
// each thread should return 0, else it detected some problem
|
|
|
|
CPPUNIT_ASSERT (threads[i]->Wait() == (wxThread::ExitCode)0);
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT( int1 == 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void *AtomicTestCase::MyThread::Entry()
|
|
|
|
{
|
|
|
|
wxInt32 negativeValuesSeen = 0;
|
|
|
|
|
|
|
|
for (wxInt32 i=0; i<10000000; ++i)
|
|
|
|
{
|
|
|
|
switch (m_testType)
|
|
|
|
{
|
|
|
|
case AtomicTestCase::IncAndDecMixed:
|
|
|
|
wxAtomicInc(m_operateOn);
|
|
|
|
wxAtomicDec(m_operateOn);
|
|
|
|
|
|
|
|
if (m_operateOn < 0)
|
|
|
|
++negativeValuesSeen;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AtomicTestCase::IncOnly:
|
|
|
|
wxAtomicInc(m_operateOn);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AtomicTestCase::DecOnly:
|
|
|
|
wxAtomicDec(m_operateOn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (wxThread::ExitCode)negativeValuesSeen;
|
|
|
|
}
|