Updating threadpool class

This commit is contained in:
Mark Berrill
2017-07-05 12:08:21 -04:00
parent c3d26ff712
commit a04317d766
14 changed files with 5020 additions and 4113 deletions

View File

@@ -2,47 +2,49 @@
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#ifndef included_ThreadPoolAtomicHelpers
#define included_ThreadPoolAtomicHelpers
#include <stdint.h>
#include <stdio.h>
#include <typeinfo>
#include <stdint.h>
#include <stdexcept>
// Choose the OS
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
// Using windows
#define USE_WINDOWS
#define NOMINMAX
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#elif defined(__APPLE__)
// Using MAC
#define USE_MAC
#include <libkern/OSAtomic.h>
#elif defined(__linux) || defined(__unix) || defined(__posix)
// Using Linux
#define USE_LINUX
#include <unistd.h>
#if !defined(__GNUC__)
#define USE_PTHREAD_ATOMIC_LOCK
#include "pthread.h"
#endif
#else
#error Unknown OS
// Choose the OS
#if defined( WIN32 ) || defined( _WIN32 ) || defined( WIN64 ) || defined( _WIN64 )
// Using windows
#define USE_WINDOWS
#define NOMINMAX
#include <process.h>
#include <stdlib.h>
#include <windows.h>
#elif defined( __APPLE__ )
// Using MAC
#define USE_MAC
#include <libkern/OSAtomic.h>
#elif defined( __linux ) || defined( __unix ) || defined( __posix )
// Using Linux
#define USE_LINUX
#include <unistd.h>
#if !defined( __GNUC__ )
#define USE_PTHREAD_ATOMIC_LOCK
#include "pthread.h"
#endif
#else
#error Unknown OS
#endif
/** \namespace atomic
* \brief Functions for atomic operations
* \details This class provides wrapper routines to access simple atomic operations.
* Since atomic operations are system dependent, these functions are necessary
* Since atomic operations are system dependent, these functions are necessary
* to provide a platform independent interface. We also provide some typedef
* variables to wrap OS dependencies. Currently we have 32 and 64 bit integers:
* int32_atomic and int64_atomic. In all cases the operations use the barrier
* versions provided by the compiler/OS if availible. In most cases, these builtins
* are considered a full barrier. That is, no memory operand will be moved across
* the operation, either forward or backward. Further, instructions will be issued
* as necessary to prevent the processor from speculating loads across the operation
* int32_atomic and int64_atomic. In all cases the operations use the barrier
* versions provided by the compiler/OS if availible. In most cases, these builtins
* are considered a full barrier. That is, no memory operand will be moved across
* the operation, either forward or backward. Further, instructions will be issued
* as necessary to prevent the processor from speculating loads across the operation
* and from queuing stores after the operation.
* Note: for all functions the variable being modified must be volatile to prevent
* compiler optimization that may cache the value.
@@ -51,280 +53,456 @@ namespace AtomicOperations {
// Define int32_atomic, int64_atomic
#include <stdint.h>
#if defined(USE_WINDOWS)
typedef long int32_atomic;
typedef __int64 int64_atomic;
#define NO_INST_ATTR
#elif defined(USE_MAC)
typedef int32_t int32_atomic;
typedef int64_t int64_atomic;
#define NO_INST_ATTR
#elif defined(__GNUC__)
typedef int int32_atomic;
typedef long int int64_atomic;
#define NO_INST_ATTR __attribute__((no_instrument_function))
#elif defined(USE_PTHREAD_ATOMIC_LOCK)
typedef int int32_atomic;
typedef long int int64_atomic;
#define NO_INST_ATTR
#if defined( USE_WINDOWS )
typedef long int32_atomic;
typedef __int64 int64_atomic;
#define NO_INST_ATTR_ATOMIC
#elif defined( USE_MAC )
typedef int32_t int32_atomic;
typedef int64_t int64_atomic;
#define NO_INST_ATTR_ATOMIC
#elif defined( __GNUC__ )
typedef int int32_atomic;
typedef long int int64_atomic;
#define NO_INST_ATTR_ATOMIC __attribute__( ( no_instrument_function ) )
#elif defined( USE_PTHREAD_ATOMIC_LOCK )
typedef int int32_atomic;
typedef long int int64_atomic;
#define NO_INST_ATTR_ATOMIC
#else
#error Unknown OS
#error Unknown OS
#endif
/**
* \brief Increment returning the new value
* \details Increment x and return the new value
* \param[in] x The pointer to the value to increment
* \brief Get the value
* \details Read the data in x
* \param[in] x The pointer to the value to get
*/
inline int32_atomic atomic_increment( int32_atomic volatile *x ) NO_INST_ATTR;
inline int32_atomic atomic_get( const int32_atomic volatile *x );
/**
* \brief Get the value
* \details Read the data in x
* \param[in] x The pointer to the value to get
*/
inline int64_atomic atomic_get( const int64_atomic volatile *x );
/**
* \brief Set the value
* \details Set the data in x to y (*x=y)
* \param[in] x The pointer to the value to set
* \param[in] y The value to set
*/
inline void atomic_set( int32_atomic volatile *x, int32_atomic y );
/**
* \brief Set the value
* \details Set the data in x to y (*x=y)
* \param[in] x The pointer to the value to set
* \param[in] y The value to set
*/
inline void atomic_set( int64_atomic volatile *x, int64_atomic y );
/**
* \brief Increment returning the new value
* \details Increment x and return the new value
* \param[in] x The pointer to the value to increment
* \param[in] x The pointer to the value to increment
*/
inline int64_atomic atomic_increment( int64_atomic volatile *x ) NO_INST_ATTR;
inline int32_atomic atomic_increment( int32_atomic volatile *x ) NO_INST_ATTR_ATOMIC;
/**
* \brief Increment returning the new value
* \details Increment x and return the new value
* \param[in] x The pointer to the value to increment
*/
inline int64_atomic atomic_increment( int64_atomic volatile *x ) NO_INST_ATTR_ATOMIC;
/**
* \brief Decrement returning the new value
* \details Decrement x and return the new value
* \param[in] x The pointer to the value to decrement
* \param[in] x The pointer to the value to decrement
*/
inline int32_atomic atomic_decrement( int32_atomic volatile *x ) NO_INST_ATTR;
inline int32_atomic atomic_decrement( int32_atomic volatile *x ) NO_INST_ATTR_ATOMIC;
/**
* \brief Decrement returning the new value
* \details Decrement x and return the new value
* \param[in] x The pointer to the value to decrement
* \param[in] x The pointer to the value to decrement
*/
inline int64_atomic atomic_decrement( int64_atomic volatile *x ) NO_INST_ATTR;
inline int64_atomic atomic_decrement( int64_atomic volatile *x ) NO_INST_ATTR_ATOMIC;
/**
* \brief Add returning the new value
* \details Add y to x and return the new value
* \param[in] x The pointer to the value to add to
* \param[in] x The pointer to the value to add to
* \param[in] y The value to add
*/
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y ) NO_INST_ATTR;
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y ) NO_INST_ATTR_ATOMIC;
/**
* \brief Add returning the new value
* \details Add y to x and return the new value
* \param[in] x The pointer to the value to add to
* \param[in] x The pointer to the value to add to
* \param[in] y The value to add
*/
inline int64_atomic atomic_add( int64_atomic volatile *x, int32_atomic y ) NO_INST_ATTR;
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y ) NO_INST_ATTR_ATOMIC;
/**
* \brief Compare the given value and swap
* \details Compare the existing value and swap if it matches.
* This function returns the previous value.
* To return a bool indicating if the swap was performed,
* use "bool t = atomic_compare_and_swap(v,x,y)==x".
* \details Compare the existing value and swap if it matches.
* \return Returns true if the swap was performed
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline int32_atomic atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y );
inline bool atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y );
/**
* \brief Compare the given value and swap
* \details Compare the existing value and swap if it matches.
* This function returns the previous value.
* To return a bool indicating if the swap was performed,
* use "bool t = atomic_compare_and_swap(v,x,y)==x".
* \details Compare the existing value and swap if it matches.
* \return Returns true if the swap was performed
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline int64_atomic atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y );
inline bool atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y );
/**
* \brief Compare the given value and swap
* \details Compare the existing value and swap if it matches.
* This function returns the previous value.
* To return a bool indicating if the swap was performed,
* use "bool t = atomic_compare_and_swap(v,x,y)==x".
* \details Compare the existing value and swap if it matches.
* \return Returns true if the swap was performed
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline void* atomic_compare_and_swap( void* volatile *v, void* x, void* y );
inline bool atomic_compare_and_swap( void *volatile *v, void *x, void *y );
/**
* \brief Fetch the current value and "and" with given value
* \details Perform *v = (*v) & x, returning the previous value
* \return Returns the previous value before the "and" operation
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline int32_atomic atomic_fetch_and_and( int32_atomic volatile *v, int32_atomic x );
/**
* \brief Fetch the current value and "and" with given value
* \details Perform *v = (*v) & x, returning the previous value
* \return Returns the previous value before the "and" operation
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline int64_atomic atomic_fetch_and_and( int64_atomic volatile *v, int64_atomic x );
/**
* \brief Fetch the current value and "or" with given value
* \details Perform *v = (*v) | x, returning the previous value
* \return Returns the previous value before the "and" operation
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline int32_atomic atomic_fetch_and_or( int32_atomic volatile *v, int32_atomic x );
/**
* \brief Fetch the current value and "ou" with given value
* \details Perform *v = (*v) | x, returning the previous value
* \return Returns the previous value before the "and" operation
* \param[in] v The pointer to the value to check and swap
* \param[in] x The value to compare
* \param[in] y The value to swap iff *v==x
*/
inline int64_atomic atomic_fetch_and_or( int64_atomic volatile *v, int64_atomic x );
/**
* \brief Class to store a pool of objects
* \details This class stores a pool of objects that can be added/removed in a thread-safe way
*/
template<class TYPE,int N_MAX>
class pool
{
public:
pool( )
{
d_data = new volatile TYPE*[N_MAX];
for (int i=0; i<N_MAX; i++)
d_data[i] = new TYPE;
}
~pool( )
{
for (int i=0; i<N_MAX; i++)
if ( d_data[i] != nullptr )
delete d_data[i];
delete [] d_data;
}
inline TYPE* get()
{
int i=0;
while ( true ) {
TYPE* tmp = const_cast<TYPE*>( d_data[i] );
bool swapped = atomic_compare_and_swap( (void* volatile*) &d_data[i], tmp, nullptr );
if ( swapped && ( tmp != nullptr ) )
return tmp;
i = (i+1)%N_MAX;
}
}
inline void put( TYPE* ptr )
{
int i = 0;
while ( !atomic_compare_and_swap( (void* volatile*) &d_data[i], nullptr, ptr ) )
i = (i+1)%N_MAX;
}
private:
volatile TYPE **d_data;
pool( const pool &rhs );
pool &operator=( const pool &rhs );
};
// Define increment/decrement/add operators for int32, int64
#if defined(USE_WINDOWS)
inline int32_atomic atomic_increment( int32_atomic volatile *x ) {
return InterlockedIncrement(x);
}
inline int64_atomic atomic_increment( int64_atomic volatile *x ) {
return InterlockedIncrement64(x);
}
inline int32_atomic atomic_decrement( int32_atomic volatile *x ) {
return InterlockedDecrement(x);
}
inline int64_atomic atomic_decrement( int64_atomic volatile *x ) {
return InterlockedDecrement64(x);
}
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y ) {
return InterlockedExchangeAdd(x,y)+y;
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y ) {
return InterlockedExchangeAdd64(x,y)+y;
}
inline int32_atomic atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y ) {
return InterlockedCompareExchange(v,x,y);
}
inline int64_atomic atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y ) {
return InterlockedCompareExchange64(v,x,y);
}
inline void* atomic_compare_and_swap( void* volatile *v, void* x, void* y ) {
return InterlockedCompareExchangePointer(v,x,y);
}
#elif defined(USE_MAC)
inline int32_atomic atomic_increment( int32_atomic volatile *x ) {
return OSAtomicIncrement32Barrier(x);
}
inline int64_atomic atomic_increment( int64_atomic volatile *x ) {
return OSAtomicIncrement64Barrier(x);
}
inline int32_atomic atomic_decrement( int32_atomic volatile *x ) {
return OSAtomicDecrement32Barrier(x);
}
inline int64_atomic atomic_decrement( int64_atomic volatile *x ) {
return OSAtomicDecrement64Barrier(x);
}
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y ) {
return OSAtomicAdd32Barrier(y,x);
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y ) {
return OSAtomicAdd64Barrier(y,x);
}
inline int32_atomic atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y ) {
return OSAtomicCompareAndSwap32Barrier(x,y,v) ? y:x;
}
inline int64_atomic atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y ) {
return OSAtomicCompareAndSwap64Barrier(x,y,v) ? y:x;
}
inline void* atomic_compare_and_swap( void* volatile *v, void* x, void* y ) {
return OSAtomicCompareAndSwapPtrBarrier(x,y,v) ? y:x;
}
#elif defined(__GNUC__)
int32_atomic atomic_increment( int32_atomic volatile *x ) {
return __sync_add_and_fetch(x,1);
}
int64_atomic atomic_increment( int64_atomic volatile *x ) {
return __sync_add_and_fetch(x,1);
}
int32_atomic atomic_decrement( int32_atomic volatile *x ) {
return __sync_sub_and_fetch(x,1);
}
int64_atomic atomic_decrement( int64_atomic volatile *x ) {
return __sync_sub_and_fetch(x,1);
}
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y ) {
return __sync_add_and_fetch(x,y);
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y ) {
return __sync_add_and_fetch(x,y);
}
inline int32_atomic atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y ) {
return __sync_val_compare_and_swap(v,x,y);
}
inline int64_atomic atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y ) {
return __sync_val_compare_and_swap(v,x,y);
}
inline void* atomic_compare_and_swap( void* volatile *v, void* x, void* y ) {
return __sync_val_compare_and_swap(v,x,y);
}
#elif defined(USE_PTHREAD_ATOMIC_LOCK)
extern pthread_mutex_t atomic_pthread_lock;
inline int32_atomic atomic_increment( int32_atomic volatile *x ) {
pthread_mutex_lock(&atomic_pthread_lock);
int32_atomic y = ++(*x);
pthread_mutex_unlock(&atomic_pthread_lock);
return y;
}
inline int64_atomic atomic_increment( int64_atomic volatile *x ) {
pthread_mutex_lock(&atomic_pthread_lock);
int64_atomic y = ++(*x);
pthread_mutex_unlock(&atomic_pthread_lock);
return y;
}
inline int32_atomic atomic_decrement( int32_atomic volatile *x ) {
pthread_mutex_lock(&atomic_pthread_lock);
int32_atomic y = --(*x);
pthread_mutex_unlock(&atomic_pthread_lock);
return y;
}
inline int64_atomic atomic_decrement( int64_atomic volatile *x ) {
pthread_mutex_lock(&atomic_pthread_lock);
int64_atomic y = --(*x);
pthread_mutex_unlock(&atomic_pthread_lock);
return y;
}
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y ) {
pthread_mutex_lock(&atomic_pthread_lock);
*x += y;
int32_atomic z = *x;
pthread_mutex_unlock(&atomic_pthread_lock);
return z;
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y ) {
pthread_mutex_lock(&atomic_pthread_lock);
*x += y;
int64_atomic z = *x;
pthread_mutex_unlock(&atomic_pthread_lock);
return z;
}
inline int32_atomic atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y ) {
pthread_mutex_lock(&atomic_pthread_lock);
*v = (*v==x) ? y:x;
int32_atomic z = *v;
pthread_mutex_unlock(&atomic_pthread_lock);
return z;
}
inline int64_atomic atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y ) {
pthread_mutex_lock(&atomic_pthread_lock);
*v = (*v==x) ? y:x;
int64_atomic z = *v;
pthread_mutex_unlock(&atomic_pthread_lock);
return z;
}
inline void* atomic_compare_and_swap( void* volatile *v, void* x, void* y ) {
pthread_mutex_lock(&atomic_pthread_lock);
*v = (*v==x) ? y:x;
void* z = *v;
pthread_mutex_unlock(&atomic_pthread_lock);
return z;
}
#if defined( USE_WINDOWS )
inline int32_atomic atomic_increment( int32_atomic volatile *x )
{
return InterlockedIncrement( x );
}
inline int64_atomic atomic_increment( int64_atomic volatile *x )
{
return InterlockedIncrement64( x );
}
inline int32_atomic atomic_decrement( int32_atomic volatile *x )
{
return InterlockedDecrement( x );
}
inline int64_atomic atomic_decrement( int64_atomic volatile *x )
{
return InterlockedDecrement64( x );
}
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y )
{
return InterlockedExchangeAdd( x, y ) + y;
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y )
{
return InterlockedExchangeAdd64( x, y ) + y;
}
inline bool atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y )
{
return InterlockedCompareExchange( v, y, x ) == x;
}
inline bool atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y )
{
return InterlockedCompareExchange64( v, y, x ) == x;
}
inline bool atomic_compare_and_swap( void *volatile *v, void *x, void *y )
{
return InterlockedCompareExchangePointer( v, x, y ) == x;
}
#elif defined( USE_MAC )
inline int32_atomic atomic_increment( int32_atomic volatile *x )
{
return OSAtomicIncrement32Barrier( x );
}
inline int64_atomic atomic_increment( int64_atomic volatile *x )
{
return OSAtomicIncrement64Barrier( x );
}
inline int32_atomic atomic_decrement( int32_atomic volatile *x )
{
return OSAtomicDecrement32Barrier( x );
}
inline int64_atomic atomic_decrement( int64_atomic volatile *x )
{
return OSAtomicDecrement64Barrier( x );
}
int32_atomic atomic_fetch_and_or( int32_atomic volatile *v, int32_atomic x ) { return OSAtomicOr32Orig( x, (volatile uint32_t *) v ); }
int32_atomic atomic_fetch_and_and( int32_atomic volatile *v, int32_atomic x ) { return OSAtomicAnd32Orig( x, (volatile uint32_t *) v); }
int64_atomic atomic_fetch_and_or( int64_atomic volatile *v, int64_atomic x ) { throw std::logic_error("Not availible for this OS"); return 0; }
int64_atomic atomic_fetch_and_and( int64_atomic volatile *v, int64_atomic x ) { throw std::logic_error("Not availible for this OS"); return 0; }
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y )
{
return OSAtomicAdd32Barrier( y, x );
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y )
{
return OSAtomicAdd64Barrier( y, x );
}
inline bool atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y )
{
return OSAtomicCompareAndSwap32Barrier( x, y, v );
}
inline bool atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y )
{
return OSAtomicCompareAndSwap64Barrier( x, y, v );
}
inline bool atomic_compare_and_swap( void *volatile *v, void *x, void *y )
{
return OSAtomicCompareAndSwapPtrBarrier( x, y, v );
}
#elif defined( __GNUC__ )
int32_atomic atomic_increment( int32_atomic volatile *x ) { return __sync_add_and_fetch( x, 1 ); }
int64_atomic atomic_increment( int64_atomic volatile *x ) { return __sync_add_and_fetch( x, 1 ); }
int32_atomic atomic_decrement( int32_atomic volatile *x ) { return __sync_sub_and_fetch( x, 1 ); }
int64_atomic atomic_decrement( int64_atomic volatile *x ) { return __sync_sub_and_fetch( x, 1 ); }
int32_atomic atomic_fetch_and_or( int32_atomic volatile *v, int32_atomic x ) { return __sync_fetch_and_or( v, x ); }
int64_atomic atomic_fetch_and_or( int64_atomic volatile *v, int64_atomic x ) { return __sync_fetch_and_or( v, x ); }
int32_atomic atomic_fetch_and_and( int32_atomic volatile *v, int32_atomic x ) { return __sync_fetch_and_and( v, x ); }
int64_atomic atomic_fetch_and_and( int64_atomic volatile *v, int64_atomic x ) { return __sync_fetch_and_and( v, x ); }
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y )
{
return __sync_add_and_fetch( x, y );
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y )
{
return __sync_add_and_fetch( x, y );
}
inline bool atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y )
{
return __sync_bool_compare_and_swap( v, x, y );
}
inline bool atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y )
{
return __sync_bool_compare_and_swap( v, x, y );
}
inline bool atomic_compare_and_swap( void *volatile *v, void *x, void *y )
{
return __sync_bool_compare_and_swap( v, x, y );
}
#elif defined( USE_PTHREAD_ATOMIC_LOCK )
extern pthread_mutex_t atomic_pthread_lock;
inline int32_atomic atomic_increment( int32_atomic volatile *x )
{
pthread_mutex_lock( &atomic_pthread_lock );
int32_atomic y = ++( *x );
pthread_mutex_unlock( &atomic_pthread_lock );
return y;
}
inline int64_atomic atomic_increment( int64_atomic volatile *x )
{
pthread_mutex_lock( &atomic_pthread_lock );
int64_atomic y = ++( *x );
pthread_mutex_unlock( &atomic_pthread_lock );
return y;
}
inline int32_atomic atomic_decrement( int32_atomic volatile *x )
{
pthread_mutex_lock( &atomic_pthread_lock );
int32_atomic y = --( *x );
pthread_mutex_unlock( &atomic_pthread_lock );
return y;
}
inline int64_atomic atomic_decrement( int64_atomic volatile *x )
{
pthread_mutex_lock( &atomic_pthread_lock );
int64_atomic y = --( *x );
pthread_mutex_unlock( &atomic_pthread_lock );
return y;
}
inline int32_atomic atomic_add( int32_atomic volatile *x, int32_atomic y )
{
pthread_mutex_lock( &atomic_pthread_lock );
*x += y;
int32_atomic z = *x;
pthread_mutex_unlock( &atomic_pthread_lock );
return z;
}
inline int64_atomic atomic_add( int64_atomic volatile *x, int64_atomic y )
{
pthread_mutex_lock( &atomic_pthread_lock );
*x += y;
int64_atomic z = *x;
pthread_mutex_unlock( &atomic_pthread_lock );
return z;
}
inline bool atomic_compare_and_swap( int32_atomic volatile *v, int32_atomic x, int32_atomic y )
{
pthread_mutex_lock( &atomic_pthread_lock );
bool test = *v == x;
*v = test ? y : x;
pthread_mutex_unlock( &atomic_pthread_lock );
return test;
}
inline bool atomic_compare_and_swap( int64_atomic volatile *v, int64_atomic x, int64_atomic y )
{
pthread_mutex_lock( &atomic_pthread_lock );
bool test = *v == x;
*v = test ? y : x;
pthread_mutex_unlock( &atomic_pthread_lock );
return test;
}
inline bool atomic_compare_and_swap( void *volatile *v, void *x, void *y )
{
pthread_mutex_lock( &atomic_pthread_lock );
bool test = *v == x;
*v = test ? y : x;
pthread_mutex_unlock( &atomic_pthread_lock );
return test;
}
#else
#error Unknown OS
#error Unknown OS
#endif
inline int32_atomic atomic_get( const int32_atomic volatile *x )
{
return atomic_add( const_cast<int32_atomic volatile *>( x ), 0 );
}
inline int64_atomic atomic_get( const int64_atomic volatile *x )
{
return atomic_add( const_cast<int64_atomic volatile *>( x ), 0 );
}
inline void atomic_set( int32_atomic volatile *x, int32_atomic y )
{
int32_atomic tmp = *x;
while ( !atomic_compare_and_swap( x, tmp, y ) ) { tmp = *x; }
}
inline void atomic_set( int64_atomic volatile *x, int64_atomic y )
{
int64_atomic tmp = *x;
while ( !atomic_compare_and_swap( x, tmp, y ) ) { tmp = *x; }
}
inline void atomic_swap( int32_atomic volatile *x, int32_atomic *y )
{
int32_atomic tmp = *x;
while ( !atomic_compare_and_swap( x, tmp, *y ) ) { tmp = *x; }
*y = tmp;
}
inline void atomic_swap( int64_atomic volatile *x, int64_atomic *y )
{
int64_atomic tmp = *x;
while ( !atomic_compare_and_swap( x, tmp, *y ) ) { tmp = *x; }
*y = tmp;
}
// Define an atomic counter
struct counter_t {
public:
// Constructor
inline counter_t(): count(0) {}
// Destructor
inline ~counter_t() {} // Destructor
// Increment returning the new value
inline int increment() { return atomic_increment(&count);}
// Decrement returning the new value
inline int decrement() { return atomic_decrement(&count);}
// Set the current value of the count
inline void setCount(int val) { count = val;}
// Get the current value of the count
inline int getCount() const { return count;}
private:
counter_t( const counter_t& );
counter_t& operator=( const counter_t& );
volatile int32_atomic count;
public:
// Constructor
inline counter_t() : count( 0 ) {}
// Destructor
inline ~counter_t() {} // Destructor
// Increment returning the new value
inline int increment() { return atomic_increment( &count ); }
// Decrement returning the new value
inline int decrement() { return atomic_decrement( &count ); }
// Set the current value of the count
inline void setCount( int val ) { count = val; }
// Get the current value of the count
inline int getCount() const { return count; }
private:
counter_t( const counter_t & );
counter_t &operator=( const counter_t & );
volatile int32_atomic count;
};
@@ -332,4 +510,3 @@ struct counter_t {
#endif