commit
9c347897b3
@ -0,0 +1,134 @@
|
|||||||
|
#ifndef CONCURRENTQUEUE_HPP
|
||||||
|
#define CONCURRENTQUEUE_HPP
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
#include "ConditionVariable.hpp"
|
||||||
|
#include "ScopedLock.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CancelledException {};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ConcurrentDeque
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ConcurrentDeque()
|
||||||
|
: m_queue()
|
||||||
|
, m_cancelled(false)
|
||||||
|
, m_mutex()
|
||||||
|
, m_condVar(m_mutex)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConcurrentDeque()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
freeDeque();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void push(const T value)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
m_queue.push_back( value );
|
||||||
|
m_condVar.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool tryPop(T &popped_value)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
if ( m_queue.empty() ) return false;
|
||||||
|
|
||||||
|
popped_value = m_queue.front();
|
||||||
|
m_queue.pop_front();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
T waitAndPop()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
|
||||||
|
while ( m_queue.empty() and not m_cancelled) {
|
||||||
|
m_condVar.wait();
|
||||||
|
}
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
|
||||||
|
T retVal = m_queue.front(); // cctor
|
||||||
|
m_queue.pop_front();
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
return m_queue.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
m_cancelled = true;
|
||||||
|
m_condVar.broadcast();
|
||||||
|
freeDeque();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = T>
|
||||||
|
typename std::enable_if< std::is_pointer<U>::value >::type
|
||||||
|
freeDeque()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
typename std::deque<T>::iterator it;
|
||||||
|
for ( it = m_queue.begin(); it != m_queue.end(); ++it )
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
m_queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = T>
|
||||||
|
typename std::enable_if< !(std::is_pointer<U>::value) >::type
|
||||||
|
freeDeque()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
m_queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cancelled()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
return m_cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
ConcurrentDeque& operator=( const ConcurrentDeque& );
|
||||||
|
ConcurrentDeque( const ConcurrentDeque& );
|
||||||
|
|
||||||
|
std::deque<T> m_queue;
|
||||||
|
bool m_cancelled;
|
||||||
|
mutable Mutex m_mutex;
|
||||||
|
ConditionVariable m_condVar;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONCURRENTQUEUE_HPP
|
@ -1,105 +0,0 @@
|
|||||||
#ifndef CONCURRENTQUEUE_HPP
|
|
||||||
#define CONCURRENTQUEUE_HPP
|
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include "Mutex.hpp"
|
|
||||||
#include "ConditionVariable.hpp"
|
|
||||||
#include "ScopedLock.hpp"
|
|
||||||
#include "Common.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CancelledException {};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class ConcurrentQueue {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
|
||||||
ConcurrentQueue()
|
|
||||||
: m_queue()
|
|
||||||
, m_cancelled(false)
|
|
||||||
, m_mutex()
|
|
||||||
, m_condVar(m_mutex)
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ConcurrentQueue()
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void push(const T task)
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
ScopedLock sl(m_mutex);
|
|
||||||
if (m_cancelled) throw CancelledException();
|
|
||||||
m_queue.push( task );
|
|
||||||
m_condVar.signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool tryPop(T &popped_value)
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
ScopedLock sl(m_mutex);
|
|
||||||
if (m_cancelled) throw CancelledException();
|
|
||||||
if ( m_queue.empty() ) return false;
|
|
||||||
|
|
||||||
popped_value = m_queue.front();
|
|
||||||
m_queue.pop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
T waitAndPop()
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
ScopedLock sl(m_mutex);
|
|
||||||
|
|
||||||
while ( m_queue.empty() and not m_cancelled) {
|
|
||||||
m_condVar.wait();
|
|
||||||
}
|
|
||||||
if (m_cancelled) throw CancelledException();
|
|
||||||
|
|
||||||
T retVal = m_queue.front(); // cctor
|
|
||||||
m_queue.pop();
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
ScopedLock sl(m_mutex);
|
|
||||||
if (m_cancelled) throw CancelledException();
|
|
||||||
return m_queue.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void cancel()
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
ScopedLock sl(m_mutex);
|
|
||||||
m_cancelled = true;
|
|
||||||
m_condVar.broadcast();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ConcurrentQueue& operator=( const ConcurrentQueue& );
|
|
||||||
ConcurrentQueue( const ConcurrentQueue& );
|
|
||||||
|
|
||||||
std::queue<T> m_queue;
|
|
||||||
bool m_cancelled;
|
|
||||||
mutable Mutex m_mutex;
|
|
||||||
ConditionVariable m_condVar;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONCURRENTQUEUE_HPP
|
|
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef MYSQL_CONNECTION_POOL_HPP
|
||||||
|
#define MYSQL_CONNECTION_POOL_HPP
|
||||||
|
|
||||||
|
#include "ObjectPool.hpp"
|
||||||
|
#include "MysqlClient.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class MysqlConnectionPool : public ObjectPool<MysqlClient *>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
MysqlConnectionPool( const char *host = NULL,
|
||||||
|
const char *user = NULL,
|
||||||
|
const char *passwd = NULL,
|
||||||
|
const char *db = NULL );
|
||||||
|
~MysqlConnectionPool();
|
||||||
|
|
||||||
|
void create();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MysqlConnectionPool(const MysqlConnectionPool&);
|
||||||
|
MysqlConnectionPool& operator=(const MysqlConnectionPool&);
|
||||||
|
|
||||||
|
const char *m_host;
|
||||||
|
const char *m_user;
|
||||||
|
const char *m_passwd;
|
||||||
|
const char *m_db;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MYSQL_CONNECTION_POOL_HPP
|
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef OBJECT_POOL_HPP
|
||||||
|
#define OBJECT_POOL_HPP
|
||||||
|
|
||||||
|
#include "ConcurrentDeque.hpp"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ObjectPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ObjectPool()
|
||||||
|
: m_pool()
|
||||||
|
, m_numberOfUsedObjects(0)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ObjectPool()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const T object) // throws CancelledException
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
m_pool.push(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
T acquire() // throws CancelledException
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
T tmp = m_pool.waitAndPop();
|
||||||
|
m_numberOfUsedObjects++;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = T>
|
||||||
|
typename std::enable_if< std::is_pointer<U>::value >::type
|
||||||
|
release(T object)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
if ( m_pool.cancelled() ) {
|
||||||
|
m_numberOfUsedObjects--;
|
||||||
|
delete object;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pool.push(object);
|
||||||
|
m_numberOfUsedObjects--;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = T>
|
||||||
|
typename std::enable_if< !(std::is_pointer<U>::value) >::type
|
||||||
|
release(T object)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
if ( m_pool.cancelled() ) {
|
||||||
|
m_numberOfUsedObjects--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pool.push(object);
|
||||||
|
m_numberOfUsedObjects--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
m_pool.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ConcurrentDeque<T> m_pool;
|
||||||
|
int m_numberOfUsedObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OBJECT_POOL_HPP
|
@ -0,0 +1,31 @@
|
|||||||
|
#include "MysqlConnectionPool.hpp"
|
||||||
|
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
MysqlConnectionPool::MysqlConnectionPool( const char *host,
|
||||||
|
const char *user,
|
||||||
|
const char *passwd,
|
||||||
|
const char *db )
|
||||||
|
: m_host(host)
|
||||||
|
, m_user(user)
|
||||||
|
, m_passwd(passwd)
|
||||||
|
, m_db(db)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlConnectionPool::~MysqlConnectionPool()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MysqlConnectionPool::create()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
|
||||||
|
MysqlClient *client = new MysqlClient ( m_host, m_user, m_passwd, m_db );
|
||||||
|
client->connect();
|
||||||
|
add(client);
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "Fixture.hpp"
|
||||||
|
|
||||||
|
#include "ObjectPool.hpp"
|
||||||
|
#include "Thread.hpp"
|
||||||
|
|
||||||
|
class TestObjectPool : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
|
||||||
|
ObjectPool<int> op;
|
||||||
|
|
||||||
|
int a(1);
|
||||||
|
op.add(a);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS( op.acquire(), a );
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPointers( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
|
||||||
|
ObjectPool<int*> op;
|
||||||
|
|
||||||
|
int *a = new int(1);
|
||||||
|
int *b = new int(2);
|
||||||
|
op.add(a);
|
||||||
|
op.add(b);
|
||||||
|
|
||||||
|
int *tmp_a = op.acquire();
|
||||||
|
int *tmp_b = op.acquire();
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS( *tmp_a, *a );
|
||||||
|
TS_ASSERT_EQUALS( *tmp_b, *b );
|
||||||
|
|
||||||
|
// release will delete them
|
||||||
|
op.release(tmp_a);
|
||||||
|
op.release(tmp_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class ObjecPoolUserThread : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjecPoolUserThread( ObjectPool<int*> &objectPool
|
||||||
|
)
|
||||||
|
: m_objectPool(objectPool)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* run()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
int *a;
|
||||||
|
try {
|
||||||
|
a = m_objectPool.acquire();
|
||||||
|
LOG( Logger::DEBUG, std::string("Acquired int: ").
|
||||||
|
append(TToStr(*a)).c_str() );
|
||||||
|
} catch ( CancelledException ex ) {
|
||||||
|
LOG( Logger::DEBUG, "Cancelled while acquiring" );
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_objectPool.release(a);
|
||||||
|
} catch ( CancelledException ex ) {
|
||||||
|
LOG( Logger::DEBUG, "Cancelled while releasing" );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectPool<int*> &m_objectPool;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testCompetingThreads( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
|
||||||
|
ObjectPool<int*> op;
|
||||||
|
|
||||||
|
ObjecPoolUserThread t1(op);
|
||||||
|
ObjecPoolUserThread t2(op);
|
||||||
|
|
||||||
|
int *a = new int(27);
|
||||||
|
op.add(a);
|
||||||
|
|
||||||
|
t1.start();
|
||||||
|
t2.start();
|
||||||
|
|
||||||
|
t1.join();
|
||||||
|
t2.join();
|
||||||
|
|
||||||
|
// no need to delete "a", dtor of the ConqurrentDeque takes care of it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testCleanUp( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
|
||||||
|
ObjectPool<int*> cop;
|
||||||
|
int *a = new int(12);
|
||||||
|
int *b = new int(13);
|
||||||
|
int *c = new int(14);
|
||||||
|
cop.add(a);
|
||||||
|
cop.add(b);
|
||||||
|
cop.add(c);
|
||||||
|
|
||||||
|
// ObjecPoolUserThread t1(cop);
|
||||||
|
// ObjecPoolUserThread t2(cop);
|
||||||
|
|
||||||
|
// t1.start();
|
||||||
|
// t2.start();
|
||||||
|
|
||||||
|
cop.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -1,35 +0,0 @@
|
|||||||
#include <cxxtest/TestSuite.h>
|
|
||||||
|
|
||||||
#define private public // need to reach private variables
|
|
||||||
|
|
||||||
#include "Common.hpp"
|
|
||||||
#include "Fixture.hpp"
|
|
||||||
#include "Mutex.hpp"
|
|
||||||
|
|
||||||
class TestPThreadWrappers : public CxxTest::TestSuite
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void testMutexBasic( void )
|
|
||||||
{
|
|
||||||
TEST_HEADER;
|
|
||||||
Mutex m;
|
|
||||||
m.lock();
|
|
||||||
TS_ASSERT_EQUALS ( m.tryLock(0), 0 );
|
|
||||||
m.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void testMutexCreate( void )
|
|
||||||
{
|
|
||||||
TEST_HEADER;
|
|
||||||
Mutex m(PTHREAD_MUTEX_ERRORCHECK);
|
|
||||||
m.lock();
|
|
||||||
TS_ASSERT_EQUALS ( m.lock(), 1 );
|
|
||||||
|
|
||||||
m.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
@ -1,35 +0,0 @@
|
|||||||
#include <cxxtest/TestSuite.h>
|
|
||||||
|
|
||||||
#define private public // need to reach Singleton's private m_instance
|
|
||||||
|
|
||||||
#include "Common.hpp"
|
|
||||||
#include "Fixture.hpp"
|
|
||||||
#include "Singleton_DCLP.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
class TestSingletonDCLPSuite : public CxxTest::TestSuite
|
|
||||||
{
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
class BasicSingleton : public Singleton_DCLP<BasicSingleton>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
int getSeven()
|
|
||||||
{
|
|
||||||
TRACE;
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void testBasic( void )
|
|
||||||
{
|
|
||||||
TEST_HEADER;
|
|
||||||
|
|
||||||
TS_ASSERT_EQUALS( BasicSingleton::getInstance()->getSeven(), 7 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
Loading…
Reference in new issue