2006-04-28 00:34:21 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Test program for The Loki Library
|
|
|
|
// Copyright (c) 2006 Richard Sposato
|
|
|
|
// Permission to use, copy, modify, distribute and sell this software for any
|
|
|
|
// purpose is hereby granted without fee, provided that the above copyright
|
|
|
|
// notice appear in all copies and that both that copyright notice and this
|
|
|
|
// permission notice appear in supporting documentation.
|
|
|
|
// The authors make no representations about the
|
|
|
|
// suitability of this software for any purpose. It is provided "as is"
|
|
|
|
// without express or implied warranty.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// $Header$
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2006-10-14 00:06:15 +00:00
|
|
|
/// @note This test uses LOKI_OBJECT_LEVEL_THREADING because StrongPtr's
|
|
|
|
/// LockableTwoRefCounts policy can't be used with a single-threaded model.
|
|
|
|
/// It requires either object-level-locking or class-level-locking.
|
2006-04-28 00:34:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <windows.h>
|
|
|
|
#include <process.h>
|
2006-10-14 00:06:15 +00:00
|
|
|
#define LOKI_WINDOWS_H
|
2006-04-28 00:34:21 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <loki/Threads.h>
|
|
|
|
#include <loki/StrongPtr.h>
|
|
|
|
#include <loki/SafeFormat.h>
|
2006-10-14 00:06:15 +00:00
|
|
|
#include <loki/ScopeGuard.h>
|
2006-04-28 00:34:21 +00:00
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
|
|
|
typedef unsigned int ( WINAPI * ThreadFunction_ )( void * );
|
|
|
|
|
|
|
|
#define LOKI_pthread_t HANDLE
|
|
|
|
|
|
|
|
#define LOKI_pthread_create(handle,attr,func,arg) \
|
|
|
|
(int)((*handle=(HANDLE) _beginthreadex (NULL,0,(ThreadFunction_)func,arg,0,NULL))==NULL)
|
|
|
|
|
2006-06-08 19:15:27 +00:00
|
|
|
#define LOKI_pthread_join(thread) \
|
2006-04-28 00:34:21 +00:00
|
|
|
((::WaitForSingleObject((thread),INFINITE)!=WAIT_OBJECT_0) || !CloseHandle(thread))
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#define LOKI_pthread_t \
|
|
|
|
pthread_t
|
|
|
|
#define LOKI_pthread_create(handle,attr,func,arg) \
|
|
|
|
pthread_create(handle,attr,func,arg)
|
2006-06-08 19:15:27 +00:00
|
|
|
#define LOKI_pthread_join(thread) \
|
|
|
|
pthread_join(thread, NULL)
|
2006-04-28 00:34:21 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace Loki;
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class Thread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
typedef void * ( * CallFunction )( void * );
|
|
|
|
|
|
|
|
Thread( CallFunction func, void * parm )
|
|
|
|
: pthread_()
|
|
|
|
, func_( func )
|
|
|
|
, parm_( parm )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssignTask( CallFunction func, void * parm )
|
|
|
|
{
|
|
|
|
func_ = func;
|
|
|
|
parm_ = parm;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Start( void )
|
|
|
|
{
|
|
|
|
return LOKI_pthread_create( &pthread_, NULL, func_, parm_ );
|
|
|
|
}
|
|
|
|
|
|
|
|
int WaitForThread( void ) const
|
|
|
|
{
|
2006-06-08 19:15:27 +00:00
|
|
|
return LOKI_pthread_join( pthread_ );
|
2006-04-28 00:34:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
LOKI_pthread_t pthread_;
|
|
|
|
CallFunction func_;
|
|
|
|
void * parm_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class ThreadPool
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ThreadPool( void ) : m_threads()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Create( size_t threadCount, Thread::CallFunction function )
|
|
|
|
{
|
|
|
|
for( size_t ii = 0; ii < threadCount; ii++ )
|
|
|
|
{
|
2006-10-14 00:06:15 +00:00
|
|
|
string buffer;
|
|
|
|
SPrintf( buffer, "Creating thread %d\n" )( ii );
|
|
|
|
cout << buffer;
|
2006-04-28 00:34:21 +00:00
|
|
|
Thread * thread = new Thread( function,
|
|
|
|
reinterpret_cast< void * >( ii ) );
|
|
|
|
m_threads.push_back( thread );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Start( void )
|
|
|
|
{
|
|
|
|
for ( size_t ii = 0; ii < m_threads.size(); ii++ )
|
2006-10-14 00:06:15 +00:00
|
|
|
{
|
|
|
|
string buffer;
|
|
|
|
SPrintf( buffer, "Starting thread %d\n" )( ii );
|
|
|
|
cout << buffer;
|
2006-04-28 00:34:21 +00:00
|
|
|
m_threads.at( ii )->Start();
|
2006-10-14 00:06:15 +00:00
|
|
|
}
|
2006-04-28 00:34:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Join( void ) const
|
|
|
|
{
|
|
|
|
for ( size_t ii = 0; ii < m_threads.size(); ii++ )
|
|
|
|
m_threads.at( ii )->WaitForThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
~ThreadPool( void )
|
|
|
|
{
|
|
|
|
for ( size_t ii = 0; ii < m_threads.size(); ii++ )
|
|
|
|
{
|
|
|
|
delete m_threads.at(ii);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
typedef std::vector< Thread * > Threads;
|
|
|
|
|
|
|
|
Threads m_threads;
|
|
|
|
};
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
static const unsigned int loop = 5;
|
|
|
|
|
|
|
|
class A
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
A( void ) {}
|
|
|
|
|
2006-10-14 00:06:15 +00:00
|
|
|
#define BIG_FOR_LOOP for( unsigned int i = 0; i < 5000000; i++ ) g++;
|
2006-04-28 00:34:21 +00:00
|
|
|
|
|
|
|
void Print( void * id ) const
|
|
|
|
{
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ----------------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ---------------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: --------------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: -------------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ------------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: -----------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ----------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ---------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: --------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: -------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ------\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: -----\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ----\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: ---\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: --\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: -\n")(id);
|
|
|
|
BIG_FOR_LOOP;Printf("%p: \n")(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
static unsigned int g;
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned int A::g = 0;
|
|
|
|
|
|
|
|
typedef Loki::StrongPtr< A, true, TwoRefCounts, DisallowConversion,
|
|
|
|
NoCheck, NeverReset, DeleteSingle, DontPropagateConst >
|
|
|
|
A_ptr;
|
|
|
|
|
|
|
|
typedef Loki::StrongPtr< A, true, LockableTwoRefCounts, DisallowConversion,
|
|
|
|
NoCheck, NeverReset, DeleteSingle, DontPropagateConst >
|
|
|
|
A_Lockable_ptr;
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class SafeA
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static SafeA & GetIt( void )
|
|
|
|
{
|
|
|
|
if ( NULL == s_instance )
|
|
|
|
s_instance = new SafeA;
|
|
|
|
return *s_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Destroy( void )
|
|
|
|
{
|
2006-10-14 00:06:15 +00:00
|
|
|
if ( NULL != s_instance )
|
2006-04-28 00:34:21 +00:00
|
|
|
{
|
|
|
|
delete s_instance;
|
|
|
|
s_instance = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
A_Lockable_ptr GetA (void) { return m_ptr; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
static SafeA * s_instance;
|
|
|
|
|
|
|
|
SafeA( void ) : m_ptr( new A ) {}
|
|
|
|
|
|
|
|
~SafeA( void ) {}
|
|
|
|
|
|
|
|
A_Lockable_ptr m_ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
SafeA * SafeA::s_instance = NULL;
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class UnsafeA
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static UnsafeA & GetIt( void )
|
|
|
|
{
|
|
|
|
if ( NULL == s_instance )
|
|
|
|
s_instance = new UnsafeA;
|
|
|
|
return *s_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Destroy( void )
|
|
|
|
{
|
2006-10-14 00:06:15 +00:00
|
|
|
if ( NULL != s_instance )
|
2006-04-28 00:34:21 +00:00
|
|
|
{
|
|
|
|
delete s_instance;
|
|
|
|
s_instance = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
A_ptr GetA (void) { return m_ptr; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
static UnsafeA * s_instance;
|
|
|
|
|
|
|
|
UnsafeA( void ) : m_ptr( new A ) {}
|
|
|
|
|
|
|
|
~UnsafeA( void ) {}
|
|
|
|
|
|
|
|
A_ptr m_ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
UnsafeA * UnsafeA::s_instance = NULL;
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void * RunLocked( void * id )
|
|
|
|
{
|
|
|
|
A_Lockable_ptr ap( SafeA::GetIt().GetA() );
|
|
|
|
for( unsigned int i = 0; i < loop; i++ )
|
|
|
|
{
|
|
|
|
ap.Lock();
|
2006-10-14 00:06:15 +00:00
|
|
|
Loki::ScopeGuard unlockGuard = MakeGuard( &A_Lockable_ptr::Unlock, ap );
|
|
|
|
(void)unlockGuard;
|
2006-04-28 00:34:21 +00:00
|
|
|
ap->Print( id );
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void * Run( void * id )
|
|
|
|
{
|
|
|
|
A_ptr ap( UnsafeA::GetIt().GetA() );
|
|
|
|
for( unsigned int i = 0; i < loop; i++ )
|
|
|
|
{
|
|
|
|
ap->Print( id );
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void DoLockedPtrTest( void )
|
|
|
|
{
|
|
|
|
SafeA::GetIt();
|
|
|
|
UnsafeA::GetIt();
|
|
|
|
::system( "pause" );
|
|
|
|
{
|
|
|
|
ThreadPool pool;
|
|
|
|
pool.Create( 5, RunLocked );
|
|
|
|
pool.Start();
|
|
|
|
pool.Join();
|
|
|
|
}
|
|
|
|
::system( "pause" );
|
|
|
|
{
|
|
|
|
ThreadPool pool;
|
|
|
|
pool.Create( 5, Run );
|
|
|
|
pool.Start();
|
|
|
|
pool.Join();
|
|
|
|
}
|
|
|
|
SafeA::Destroy();
|
|
|
|
UnsafeA::Destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// $Log$
|
2006-10-14 00:06:15 +00:00
|
|
|
// Revision 1.3 2006/10/14 00:06:15 rich_sposato
|
|
|
|
// Fixed a couple of bugs. Added lines to send test info to output. Added
|
|
|
|
// use of ScopeGuard. Removed superfluous code.
|
|
|
|
//
|
2006-06-08 19:15:27 +00:00
|
|
|
// Revision 1.2 2006/06/08 19:15:27 lfittl
|
|
|
|
// - Simplify some threading code by not saving the return status
|
|
|
|
// (also fixes 2 gcc warnings)
|
|
|
|
//
|
2006-04-28 00:34:21 +00:00
|
|
|
// Revision 1.1 2006/04/28 00:34:21 rich_sposato
|
|
|
|
// Added test for thread-safe StrongPtr policy.
|
|
|
|
//
|