This is easy to do and can be useful when using an atomic initialization counter. The only platform where not returning the new value might be more efficient than returning it is Solaris which is not really relevant any more and on all the other platforms the functions we were already using provided this value already (or almost, in case of using gcc builtins, when we just have to use a different one).
173 lines
4.3 KiB
C++
173 lines
4.3 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/thread/atomic.cpp
|
|
// Purpose: wxAtomic??? unit test
|
|
// Author: Armel Asselin
|
|
// Created: 2006-12-14
|
|
// Copyright: (c) 2006 Armel Asselin
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "testprec.h"
|
|
|
|
|
|
#ifndef WX_PRECOMP
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/atomic.h"
|
|
#include "wx/thread.h"
|
|
#include "wx/dynarray.h"
|
|
#include "wx/log.h"
|
|
#include "wx/vector.h"
|
|
|
|
typedef wxVector<wxThread*> wxArrayThread;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// constants
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static const wxInt32 ITERATIONS_NUM = 10000;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// test helper thread
|
|
// ----------------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
enum ETestType
|
|
{
|
|
IncAndDecMixed,
|
|
IncOnly,
|
|
DecOnly
|
|
};
|
|
|
|
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() wxOVERRIDE;
|
|
|
|
public:
|
|
wxAtomicInt &m_operateOn;
|
|
ETestType m_testType;
|
|
};
|
|
} // anonymous namespace
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// the tests themselves
|
|
// ----------------------------------------------------------------------------
|
|
|
|
TEST_CASE("Atomic::NoThread", "[atomic]")
|
|
{
|
|
wxAtomicInt int1 = 0,
|
|
int2 = 0;
|
|
|
|
for ( wxInt32 i = 0; i < ITERATIONS_NUM; ++i )
|
|
{
|
|
wxAtomicInc(int1);
|
|
wxAtomicDec(int2);
|
|
}
|
|
|
|
CHECK( int1 == ITERATIONS_NUM );
|
|
CHECK( int2 == -ITERATIONS_NUM );
|
|
}
|
|
|
|
TEST_CASE("Atomic::ReturnValue", "[atomic]")
|
|
{
|
|
wxAtomicInt i(0);
|
|
REQUIRE( wxAtomicInc(i) == 1 );
|
|
REQUIRE( wxAtomicInc(i) == 2 );
|
|
|
|
REQUIRE( wxAtomicDec(i) == 1 );
|
|
REQUIRE( wxAtomicDec(i) == 0 );
|
|
}
|
|
|
|
TEST_CASE("Atomic::WithThreads", "[atomic]")
|
|
{
|
|
int count;
|
|
ETestType testType;
|
|
|
|
SECTION( "2 threads using inc and dec") { count = 2; testType = IncAndDecMixed; }
|
|
SECTION("10 threads using inc and dec") { count = 10; testType = IncAndDecMixed; }
|
|
SECTION( "2 threads using inc or dec" ) { count = 2; testType = IncOnly; }
|
|
SECTION("10 threads using inc or dec" ) { count = 10; testType = IncOnly; }
|
|
|
|
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!"));
|
|
delete thread;
|
|
}
|
|
else
|
|
threads.push_back(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
|
|
CHECK (threads[i]->Wait() == (wxThread::ExitCode)0);
|
|
delete threads[i];
|
|
}
|
|
|
|
CHECK( int1 == 0 );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void *MyThread::Entry()
|
|
{
|
|
wxInt32 negativeValuesSeen = 0;
|
|
|
|
for ( wxInt32 i = 0; i < ITERATIONS_NUM; ++i )
|
|
{
|
|
switch ( m_testType )
|
|
{
|
|
case IncAndDecMixed:
|
|
wxAtomicInc(m_operateOn);
|
|
if ( wxAtomicDec(m_operateOn) < 0 )
|
|
++negativeValuesSeen;
|
|
break;
|
|
|
|
case IncOnly:
|
|
wxAtomicInc(m_operateOn);
|
|
break;
|
|
|
|
case DecOnly:
|
|
wxAtomicDec(m_operateOn);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return wxUIntToPtr(negativeValuesSeen);
|
|
}
|