From 9ea53b322c61d9c5bd2e4c07452694636189fd4b Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sat, 12 Nov 2011 17:53:33 +0100 Subject: [PATCH 1/5] new classes: ObjectPool, MysqlConnectionPool --- include/ConcurrentQueue.hpp | 4 +-- include/MysqlConnectionPool.hpp | 27 ++++++++++++++ include/ObjectPool.hpp | 29 +++++++++++++++ src/MysqlConnectionPool.cpp | 47 ++++++++++++++++++++++++ src/ObjectPool.cpp | 63 +++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 include/MysqlConnectionPool.hpp create mode 100644 include/ObjectPool.hpp create mode 100644 src/MysqlConnectionPool.cpp create mode 100644 src/ObjectPool.cpp diff --git a/include/ConcurrentQueue.hpp b/include/ConcurrentQueue.hpp index 437cbc7..9190a38 100644 --- a/include/ConcurrentQueue.hpp +++ b/include/ConcurrentQueue.hpp @@ -34,12 +34,12 @@ class ConcurrentQueue { } - void push(const T task) + void push(const T value) { TRACE; ScopedLock sl(m_mutex); if (m_cancelled) throw CancelledException(); - m_queue.push( task ); + m_queue.push( value ); m_condVar.signal(); } diff --git a/include/MysqlConnectionPool.hpp b/include/MysqlConnectionPool.hpp new file mode 100644 index 0000000..0577311 --- /dev/null +++ b/include/MysqlConnectionPool.hpp @@ -0,0 +1,27 @@ +#ifndef MYSQL_CONNECTION_POOL_HPP +#define MYSQL_CONNECTION_POOL_HPP + +#include "ObjectPool.hpp" +#include "MysqlClient.hpp" + + +class MysqlConnectionPool : public ObjectPool +{ +public: + + MysqlConnectionPool(); + ~MysqlConnectionPool(); + + MysqlClient* create( const char *host = NULL, + const char *user = NULL, + const char *passwd = NULL, + const char *db = NULL, + unsigned int port = 0, + const char *unix_socket = NULL, + unsigned long clientflag = 0 ); + + bool reset(const MysqlClient* client); +}; + + +#endif // MYSQL_CONNECTION_POOL_HPP diff --git a/include/ObjectPool.hpp b/include/ObjectPool.hpp new file mode 100644 index 0000000..0085bf4 --- /dev/null +++ b/include/ObjectPool.hpp @@ -0,0 +1,29 @@ +#ifndef OBJECT_POOL_HPP +#define OBJECT_POOL_HPP + +#include "ConcurrentQueue.hpp" + +template +class ObjectPool +{ +public: + + ObjectPool(); + virtual ~ObjectPool(); + + void add(const T object); + void remove(const T object); + void clear(); + + T get(); + virtual void reset(const T object) = 0; + void release(const T object); + + +private: + + ConcurrentQueue m_pool; + +}; + +#endif // OBJECT_POOL_HPP diff --git a/src/MysqlConnectionPool.cpp b/src/MysqlConnectionPool.cpp new file mode 100644 index 0000000..0e1e098 --- /dev/null +++ b/src/MysqlConnectionPool.cpp @@ -0,0 +1,47 @@ +#include "MysqlConnectionPool.hpp" + +#include "Logger.hpp" + + +MysqlConnectionPool::MysqlConnectionPool() +{ + TRACE; +} + + +MysqlConnectionPool::~MysqlConnectionPool() +{ + TRACE; +} + + +MysqlClient* MysqlConnectionPool::create( const char* host, + const char* user, + const char* passwd, + const char* db, + unsigned int port, + const char* unix_socket, + long unsigned int clientflag ) +{ + TRACE; + + MysqlClient *client = new MysqlClient(host, + user, + passwd, + db, + port, + unix_socket, + clientflag); + + return client; +} + + +bool MysqlConnectionPool::reset(const MysqlClient* client) +{ + TRACE; + + // The MysqlClient is stateless + + return true; +} \ No newline at end of file diff --git a/src/ObjectPool.cpp b/src/ObjectPool.cpp new file mode 100644 index 0000000..f108379 --- /dev/null +++ b/src/ObjectPool.cpp @@ -0,0 +1,63 @@ +#include "ObjectPool.hpp" + +#include "Logger.hpp" + + +template +ObjectPool::ObjectPool() + : m_pool() +{ + TRACE; +} + + +template +ObjectPool::~ObjectPool() +{ + TRACE; +} + + +template +void ObjectPool::add(const T object) +{ + TRACE; + m_pool.push(object); +} + + +template +void ObjectPool::remove(const T object) +{ + TRACE; + +// m_pool.tryPop(object); +} + + +template +void ObjectPool::clear() +{ + TRACE; + +// while ( !m_pool.empty() ) +// m_pool. +} + + +template +T ObjectPool::get() +{ + TRACE; + + return m_pool.waitAndPop(); +} + + +template +void ObjectPool::release(const T object) +{ + TRACE; + + m_pool.push(object); +} From c1fbd3bf9b52354ffbf83e1515181a0c2092e6e4 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sun, 13 Nov 2011 12:24:24 +0100 Subject: [PATCH 2/5] ObjectPool, MysqlConnectionPool fixes --- include/ConcurrentQueue.hpp | 152 ++++++++++++++++---------------- include/MysqlConnectionPool.hpp | 27 ++++-- include/ObjectPool.hpp | 36 ++++++-- other/mysqlclient_main.cpp | 118 +++++++++++++++---------- src/MysqlConnectionPool.cpp | 41 ++++----- src/ObjectPool.cpp | 63 ------------- 6 files changed, 208 insertions(+), 229 deletions(-) delete mode 100644 src/ObjectPool.cpp diff --git a/include/ConcurrentQueue.hpp b/include/ConcurrentQueue.hpp index 9190a38..3b2da6e 100644 --- a/include/ConcurrentQueue.hpp +++ b/include/ConcurrentQueue.hpp @@ -2,6 +2,7 @@ #define CONCURRENTQUEUE_HPP #include +#include #include "Mutex.hpp" #include "ConditionVariable.hpp" @@ -14,91 +15,90 @@ class CancelledException {}; template -class ConcurrentQueue { - - public: - - - ConcurrentQueue() - : m_queue() - , m_cancelled(false) - , m_mutex() - , m_condVar(m_mutex) - { - TRACE; - } - - ~ConcurrentQueue() - { - TRACE; - } - - - void push(const T value) - { - TRACE; - ScopedLock sl(m_mutex); - if (m_cancelled) throw CancelledException(); - m_queue.push( 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(); - return true; +class ConcurrentQueue +{ +public: + + ConcurrentQueue() + : m_queue() + , m_cancelled(false) + , m_mutex() + , m_condVar(m_mutex) + { + TRACE; + } + + ~ConcurrentQueue() + { + TRACE; + } + + + void push(const T value) + { + TRACE; + ScopedLock sl(m_mutex); + if (m_cancelled) throw CancelledException(); + m_queue.push( 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(); + 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; + } - 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(); + } - 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(); - } + void cancel() + { + TRACE; + ScopedLock sl(m_mutex); + m_cancelled = true; + m_condVar.broadcast(); + } - private: +private: - ConcurrentQueue& operator=( const ConcurrentQueue& ); - ConcurrentQueue( const ConcurrentQueue& ); + ConcurrentQueue& operator=( const ConcurrentQueue& ); + ConcurrentQueue( const ConcurrentQueue& ); - std::queue m_queue; - bool m_cancelled; - mutable Mutex m_mutex; - ConditionVariable m_condVar; + std::queue m_queue; + bool m_cancelled; + mutable Mutex m_mutex; + ConditionVariable m_condVar; }; diff --git a/include/MysqlConnectionPool.hpp b/include/MysqlConnectionPool.hpp index 0577311..9b3f069 100644 --- a/include/MysqlConnectionPool.hpp +++ b/include/MysqlConnectionPool.hpp @@ -9,18 +9,27 @@ class MysqlConnectionPool : public ObjectPool { public: - MysqlConnectionPool(); - ~MysqlConnectionPool(); - - MysqlClient* create( const char *host = NULL, + MysqlConnectionPool( const char *host = NULL, const char *user = NULL, const char *passwd = NULL, - const char *db = NULL, - unsigned int port = 0, - const char *unix_socket = NULL, - unsigned long clientflag = 0 ); + const char *db = NULL ); + ~MysqlConnectionPool(); + + void create(); + + /// @note Shall this be a specialized ObjectPool::clear? + 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; - bool reset(const MysqlClient* client); }; diff --git a/include/ObjectPool.hpp b/include/ObjectPool.hpp index 0085bf4..af6ed6b 100644 --- a/include/ObjectPool.hpp +++ b/include/ObjectPool.hpp @@ -2,28 +2,46 @@ #define OBJECT_POOL_HPP #include "ConcurrentQueue.hpp" +#include "Logger.hpp" template class ObjectPool { public: - ObjectPool(); - virtual ~ObjectPool(); + ObjectPool() : m_pool() + { + TRACE; + } - void add(const T object); - void remove(const T object); - void clear(); + virtual ~ObjectPool() + { + TRACE; + } - T get(); - virtual void reset(const T object) = 0; - void release(const T object); + + T acquire() + { + TRACE; + return m_pool.waitAndPop(); + } + + void release(const T object) + { + TRACE; + m_pool.push(object); + } + + bool empty() const + { + TRACE; + return m_pool.empty(); + } private: ConcurrentQueue m_pool; - }; #endif // OBJECT_POOL_HPP diff --git a/other/mysqlclient_main.cpp b/other/mysqlclient_main.cpp index a3ea231..dae693b 100644 --- a/other/mysqlclient_main.cpp +++ b/other/mysqlclient_main.cpp @@ -6,6 +6,8 @@ #include "ArgParse.hpp" #include "MysqlClient.hpp" +#include "MysqlConnectionPool.hpp" + #include #include @@ -15,9 +17,12 @@ void setUpArgs(ArgParse &argParse) { + TRACE_STATIC; + argParse.addArgument("--host", "Hostname/IP", - ArgParse::STRING ); + ArgParse::STRING, + ArgParse::REQUIRED ); argParse.addArgument("-u, --user", "Username", ArgParse::STRING, @@ -30,14 +35,9 @@ void setUpArgs(ArgParse &argParse) "Password", ArgParse::STRING, ArgParse::REQUIRED ); - argParse.addArgument("-port", - "Port", - ArgParse::INT ); - argParse.addArgument("-s, --unix-socket", - "Unix socket", - ArgParse::STRING ); - argParse.addArgument("-f, --client-flags", - "Client flags", + + argParse.addArgument("-n, --number-of-connections", + "Number of connections. Default is 5", ArgParse::INT ); } @@ -48,24 +48,59 @@ void getArgs( int argc, char* argv[], std::string &user, std::string &db, std::string &pass, - std::string &unixsocket, - int &port, - int &clientflags ) + int &numberOfConnections ) { + TRACE_STATIC; + argParse.parseArgs(argc, argv); argParse.argAsString("--host", host); argParse.argAsString("-u, --user", user); argParse.argAsString("-db, --database", db); argParse.argAsString("-p, --password", pass); - argParse.argAsInt("-port", port); - argParse.argAsString("-s, --unix-socket", unixsocket); - argParse.argAsInt("-f, --client-flags", clientflags); + + argParse.argAsInt("-n, --number-of-connections", numberOfConnections); +} + + +bool checkArgs( int argc, char* argv[], + ArgParse &argParse, + std::string &host, + std::string &user, + std::string &db, + std::string &pass, + int &numberOfConnections ) +{ + TRACE_STATIC; + + try { + getArgs( argc, argv, + argParse, + host, user, db, pass, + numberOfConnections ); + } catch (std::runtime_error e) { + if ( argParse.foundArg("-h, --help") ) { + std::cout << argParse.usage() << std::endl; + return false; + } + std::cerr << e.what() << std::endl + << "Check usage: " << argv[0] << " --help" << std::endl; + return false; + } + + if ( argParse.foundArg("-h, --help") ) { + std::cout << argParse.usage() << std::endl; + return false; + } + + return true; } void printResults(std::list &results) { + TRACE_STATIC; + LOG ( Logger::DEBUG, std::string("Got query result number of rows: "). append(TToStr(results.size())).c_str() ); @@ -83,55 +118,44 @@ int main(int argc, char* argv[] ) Logger::init(std::cout); Logger::setLogLevel(Logger::FINEST); + + // args ArgParse argParse("Simple MySQL client", "Report bugs to: denes.matetelki@gmail.com"); - setUpArgs(argParse); - std::string host, user, db, pass, unixsocket; - int port, clientflags; - - try { - getArgs( argc, argv, - argParse, - host, user, db, pass, unixsocket, - port, clientflags ); - } catch (std::runtime_error e) { - if ( argParse.foundArg("-h, --help") ) { - std::cout << argParse.usage() << std::endl; - return 1; - } - std::cerr << e.what() << std::endl - << "Check usage: " << argv[0] << " --help" << std::endl; - return 1; - } - + std::string host, user, db, pass; + int numberOfConnections(5); - if ( argParse.foundArg("-h, --help") ) { - std::cout << argParse.usage() << std::endl; + if ( !checkArgs(argc, argv, argParse, + host, user, db, pass, numberOfConnections ) ) return 1; - } + // init init_client_errs(); + MysqlConnectionPool cp ( + argParse.foundArg("--host") ? host.c_str() : NULL, + argParse.foundArg("-u, --user") ? user.c_str() : NULL, + argParse.foundArg("-p, --password") ? pass.c_str() : NULL, + argParse.foundArg("-db, --database") ? db .c_str() : NULL ); + + for ( int i = 0; i < numberOfConnections; ++i ) + cp.create(); - MysqlClient mysqlClient ( - argParse.foundArg("--host") ? host.c_str() : NULL, - argParse.foundArg("-u, --user") ? user.c_str() : NULL, - argParse.foundArg("-p, --password") ? pass.c_str() : NULL, - argParse.foundArg("-db, --database") ? db .c_str() : NULL, - argParse.foundArg("-port") ? port : 0, - argParse.foundArg("-s, --unix-socket") ? unixsocket.c_str() : NULL, - argParse.foundArg("-f, --client-flags") ? clientflags : 0 ); + // work std::list results; - if ( !mysqlClient.querty("SELECT * FROM seats", results) ) { + MysqlClient *c = cp.acquire(); + if ( !c->querty("SELECT * FROM seats", results) ) { LOG ( Logger::ERR, "Could not execute query." ); } else { printResults(results); } + cp.release(c); + // end + cp.clear(); finish_client_errs(); - Logger::destroy(); return 0; } diff --git a/src/MysqlConnectionPool.cpp b/src/MysqlConnectionPool.cpp index 0e1e098..07259bb 100644 --- a/src/MysqlConnectionPool.cpp +++ b/src/MysqlConnectionPool.cpp @@ -3,45 +3,36 @@ #include "Logger.hpp" -MysqlConnectionPool::MysqlConnectionPool() +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; } -MysqlClient* MysqlConnectionPool::create( const char* host, - const char* user, - const char* passwd, - const char* db, - unsigned int port, - const char* unix_socket, - long unsigned int clientflag ) +void MysqlConnectionPool::create() { TRACE; - MysqlClient *client = new MysqlClient(host, - user, - passwd, - db, - port, - unix_socket, - clientflag); - - return client; + MysqlClient *client = new MysqlClient ( m_host, m_user, m_passwd, m_db ); + client->connect(); + release(client); } - -bool MysqlConnectionPool::reset(const MysqlClient* client) +void MysqlConnectionPool::clear() { TRACE; - - // The MysqlClient is stateless - - return true; -} \ No newline at end of file + while ( !empty() ) + delete acquire(); +} diff --git a/src/ObjectPool.cpp b/src/ObjectPool.cpp deleted file mode 100644 index f108379..0000000 --- a/src/ObjectPool.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "ObjectPool.hpp" - -#include "Logger.hpp" - - -template -ObjectPool::ObjectPool() - : m_pool() -{ - TRACE; -} - - -template -ObjectPool::~ObjectPool() -{ - TRACE; -} - - -template -void ObjectPool::add(const T object) -{ - TRACE; - m_pool.push(object); -} - - -template -void ObjectPool::remove(const T object) -{ - TRACE; - -// m_pool.tryPop(object); -} - - -template -void ObjectPool::clear() -{ - TRACE; - -// while ( !m_pool.empty() ) -// m_pool. -} - - -template -T ObjectPool::get() -{ - TRACE; - - return m_pool.waitAndPop(); -} - - -template -void ObjectPool::release(const T object) -{ - TRACE; - - m_pool.push(object); -} From 0f69afd01db455a79547b3fd5a12aa23928ba7f4 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sun, 13 Nov 2011 15:37:44 +0100 Subject: [PATCH 3/5] cleanup at unittest files --- include/Singleton_DCLP.hpp | 5 +++ include/Singleton_call_once.hpp | 5 +++ {test => other}/test_TimerThreadMultimap.hpp | 0 src/Thread.cpp | 3 ++ test/CMakeLists.txt | 26 ++++++------ test/run_test.sh | 3 +- test/test_PThreadWrappers.hpp | 35 ---------------- test/test_Semaphore.hpp | 5 +++ test/test_Singelton_DCLP.hpp | 35 ---------------- test/test_Singleton_DCLP.hpp | 1 + ..._once.hpp => test_Singleton_call_once.hpp} | 1 + test/test_Thread.hpp | 42 +++++++++++-------- test/valgrind.supp | 13 +++++- 13 files changed, 70 insertions(+), 104 deletions(-) rename {test => other}/test_TimerThreadMultimap.hpp (100%) delete mode 100644 test/test_PThreadWrappers.hpp delete mode 100644 test/test_Singelton_DCLP.hpp rename test/{test_Singelton_call_once.hpp => test_Singleton_call_once.hpp} (94%) diff --git a/include/Singleton_DCLP.hpp b/include/Singleton_DCLP.hpp index 07ead7f..55da169 100644 --- a/include/Singleton_DCLP.hpp +++ b/include/Singleton_DCLP.hpp @@ -39,6 +39,11 @@ public: return m_instance; } + static void destroy() + { + delete m_instance; + } + private: diff --git a/include/Singleton_call_once.hpp b/include/Singleton_call_once.hpp index 117a913..3d8de36 100644 --- a/include/Singleton_call_once.hpp +++ b/include/Singleton_call_once.hpp @@ -24,6 +24,11 @@ public: return m_instance; } + static void destroy() + { + delete m_instance; + } + private: static void do_init() diff --git a/test/test_TimerThreadMultimap.hpp b/other/test_TimerThreadMultimap.hpp similarity index 100% rename from test/test_TimerThreadMultimap.hpp rename to other/test_TimerThreadMultimap.hpp diff --git a/src/Thread.cpp b/src/Thread.cpp index 2f735d0..f4c6f75 100644 --- a/src/Thread.cpp +++ b/src/Thread.cpp @@ -33,6 +33,9 @@ void Thread::start() void* Thread::join() const { TRACE; + if ( !m_isRunning ) + return 0; + void* retVal; pthread_join( m_threadHandler, &retVal ); return retVal; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0b0bfe3..56e6b87 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,20 +18,20 @@ if(CXXTEST_FOUND) generated_main.cpp Fixture.hpp -# test_ArgParse.hpp -# test_Singelton_call_once.hpp -# test_Singleton.hpp -# test_Singleton_meyers.hpp -# test_Singleton_DCLP.hpp -# test_Mutex.hpp -# test_ScopedLock.hpp -# test_ConditionalVariable.hpp + test_ArgParse.hpp + test_Common.hpp + test_ConditionalVariable.hpp + test_Multiton.hpp + test_Mutex.hpp + test_ScopedLock.hpp + test_Semaphore.hpp + test_Singleton_DCLP.hpp + test_Singleton_call_once.hpp + # test_Singleton.hpp Cannot test private member, Ficture.hpp loads it + test_Singleton_meyers.hpp test_Thread.hpp -# test_ThreadPool.hpp -# test_Semaphore.hpp -# test_Timer.hpp -# test_Common.hpp -# test_TimerThreadMultimap.hpp + test_ThreadPool.hpp + # test_Timer.hpp Takes too much time&buggy ) target_link_libraries(testCppUtils CppUtils gcov) endif() diff --git a/test/run_test.sh b/test/run_test.sh index 1d4b474..2322f5b 100755 --- a/test/run_test.sh +++ b/test/run_test.sh @@ -65,8 +65,7 @@ valgrind \ $test | tee $test.out; retval=$PIPESTATUS # NOTE to gen suppressions run: -# valgrind --leak-check=full --show-reachable=yes --show-below-main=no --track-origins=yes --num-callers=30 --malloc-fill=0xaa --free-fill=0xdd --gen-suppressions=yes ./test - +# valgrind --leak-check=full --show-reachable=yes --show-below-main=no --track-origins=yes --num-callers=30 --malloc-fill=0xaa --free-fill=0xdd --suppressions=valgrind.supp --gen-suppressions=yes ./testCppUtils # retval is 0 on success # or the number of failed cases diff --git a/test/test_PThreadWrappers.hpp b/test/test_PThreadWrappers.hpp deleted file mode 100644 index 471e30b..0000000 --- a/test/test_PThreadWrappers.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#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(); - } - - -}; diff --git a/test/test_Semaphore.hpp b/test/test_Semaphore.hpp index 36c8933..036be00 100644 --- a/test/test_Semaphore.hpp +++ b/test/test_Semaphore.hpp @@ -34,6 +34,7 @@ private: { TRACE; } + ~ThreadClassWithSemaphore() { TRACE; } @@ -94,6 +95,8 @@ public: TS_ASSERT_EQUALS( t2->release(), true ); TS_ASSERT_EQUALS( semaphore.getCount(), 1 ); + + // t2 releases instead of the using t1 TS_ASSERT_EQUALS( t2->release(), true ); TS_ASSERT_EQUALS( semaphore.getCount(), 2 ); TS_ASSERT_EQUALS( t2->release(), false ); @@ -102,6 +105,8 @@ public: t2->stop(); t1->join(); t2->join(); + + sleep(1); delete t1; delete t2; } diff --git a/test/test_Singelton_DCLP.hpp b/test/test_Singelton_DCLP.hpp deleted file mode 100644 index d5089b3..0000000 --- a/test/test_Singelton_DCLP.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#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 - { - public: - int getSeven() - { - TRACE; - return 7; - } - }; - -public: - - void testBasic( void ) - { - TEST_HEADER; - - TS_ASSERT_EQUALS( BasicSingleton::getInstance()->getSeven(), 7 ); - } - - -}; diff --git a/test/test_Singleton_DCLP.hpp b/test/test_Singleton_DCLP.hpp index d5089b3..8c1fb20 100644 --- a/test/test_Singleton_DCLP.hpp +++ b/test/test_Singleton_DCLP.hpp @@ -29,6 +29,7 @@ public: TEST_HEADER; TS_ASSERT_EQUALS( BasicSingleton::getInstance()->getSeven(), 7 ); + BasicSingleton::destroy(); } diff --git a/test/test_Singelton_call_once.hpp b/test/test_Singleton_call_once.hpp similarity index 94% rename from test/test_Singelton_call_once.hpp rename to test/test_Singleton_call_once.hpp index 873530a..9da22fa 100644 --- a/test/test_Singelton_call_once.hpp +++ b/test/test_Singleton_call_once.hpp @@ -29,6 +29,7 @@ public: TEST_HEADER; TS_ASSERT_EQUALS( BasicSingleton::getInstance()->getSeven(), 7 ); + BasicSingleton::destroy(); } diff --git a/test/test_Thread.hpp b/test/test_Thread.hpp index 7b2a00f..a5fc5fc 100644 --- a/test/test_Thread.hpp +++ b/test/test_Thread.hpp @@ -34,18 +34,14 @@ public: void testBasic( void ) { TEST_HEADER; - ThreadClass *m = new ThreadClass; - m->start(); + ThreadClass m; + m.start(); - void *retVal = m->join(); + void *retVal = m.join(); TS_ASSERT_EQUALS ( *((int*)retVal) , 14 ); free(retVal); - delete m; } -/** - * @note send a signal to a thread - */ private: @@ -62,7 +58,6 @@ private: TRACE; } - private: void* run( void ) { @@ -73,10 +68,9 @@ private: */ sleep(665); -// void* retVal = malloc(sizeof(int)); -// *((int*)retVal) = 15; -// return retVal; - return 0; + void* retVal = malloc(sizeof(int)); + *((int*)retVal) = 15; + return retVal; } static void signal_handler(int sig) @@ -97,18 +91,17 @@ public: void testSignalSend( void ) { TEST_HEADER; - ThreadClassWithSignal *m2 = new ThreadClassWithSignal; - m2->start(); + ThreadClassWithSignal m2 ; + m2.start(); sleep(1); - m2->sendSignal(SIGINT); + m2.sendSignal(SIGINT); - void *retVal = m2->join(); + void *retVal = m2.join(); TS_ASSERT(retVal); if (retVal != 0 ) { TS_ASSERT_EQUALS ( *((int*)retVal) , 16 ); free((int*)retVal); } - delete m2; } @@ -127,7 +120,7 @@ private: public: - void testEmpty( void ) + void eetestEmpty( void ) { TEST_HEADER; @@ -138,4 +131,17 @@ public: void *retVal = e.join(); TS_ASSERT_EQUALS ( retVal , (void *)0 ); } + + void testJoiningNotStartedThread( void ) + { + TEST_HEADER; + + EmptyThreadClass e; + + e.stop(); + e.join(); + void *retVal = e.join(); + TS_ASSERT_EQUALS ( retVal , (void *)0 ); + } + }; diff --git a/test/valgrind.supp b/test/valgrind.supp index 77628ba..edd82f0 100644 --- a/test/valgrind.supp +++ b/test/valgrind.supp @@ -69,7 +69,18 @@ Memcheck:Leak fun:calloc fun:_dl_allocate_tls - fun:pthread_create@@GLIBC_*.*.* + fun:pthread_create@@GLIBC_* + ... + fun:main +} + +{ + create thread2 + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_* ... fun:main } From 8aecc599163e73fe17bd0c52372c0216b00d70e8 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sun, 13 Nov 2011 22:56:01 +0100 Subject: [PATCH 4/5] Lost in the template specialization - type as pointer deduction jungle --- include/ConcurrentQueue.hpp | 36 ++++++++-- include/ObjectPool.hpp | 47 +++++++++++-- include/Thread.hpp | 8 +-- src/MysqlConnectionPool.cpp | 9 +-- src/ThreadPool.cpp | 3 +- test/CMakeLists.txt | 29 ++++---- test/test_ObjectPool.hpp | 130 ++++++++++++++++++++++++++++++++++++ test/test_Semaphore.hpp | 1 - 8 files changed, 222 insertions(+), 41 deletions(-) create mode 100644 test/test_ObjectPool.hpp diff --git a/include/ConcurrentQueue.hpp b/include/ConcurrentQueue.hpp index 3b2da6e..57e309e 100644 --- a/include/ConcurrentQueue.hpp +++ b/include/ConcurrentQueue.hpp @@ -1,7 +1,7 @@ #ifndef CONCURRENTQUEUE_HPP #define CONCURRENTQUEUE_HPP -#include +#include #include #include "Mutex.hpp" @@ -39,7 +39,7 @@ public: TRACE; ScopedLock sl(m_mutex); if (m_cancelled) throw CancelledException(); - m_queue.push( value ); + m_queue.push_back( value ); m_condVar.signal(); } @@ -52,7 +52,7 @@ public: if ( m_queue.empty() ) return false; popped_value = m_queue.front(); - m_queue.pop(); + m_queue.pop_front(); return true; } @@ -68,7 +68,7 @@ public: if (m_cancelled) throw CancelledException(); T retVal = m_queue.front(); // cctor - m_queue.pop(); + m_queue.pop_front(); return retVal; } @@ -82,20 +82,44 @@ public: } - void cancel() + void cancel(T a) { TRACE; ScopedLock sl(m_mutex); m_cancelled = true; m_condVar.broadcast(); + + m_queue.clear(); + } + + void cancel(T *a) + { + TRACE; + ScopedLock sl(m_mutex); + m_cancelled = true; + m_condVar.broadcast(); + + typename std::deque::iterator it; + for ( it = m_queue.begin(); it != m_queue.end(); ++it ) { + LOG( Logger::INFO, std::string("Deleting: ").append(*it).c_str() ); + delete *it; + } + m_queue.clear(); + } + + bool cancelled() + { + TRACE; + return m_cancelled; } private: + ConcurrentQueue& operator=( const ConcurrentQueue& ); ConcurrentQueue( const ConcurrentQueue& ); - std::queue m_queue; + std::deque m_queue; bool m_cancelled; mutable Mutex m_mutex; ConditionVariable m_condVar; diff --git a/include/ObjectPool.hpp b/include/ObjectPool.hpp index af6ed6b..8fdb63d 100644 --- a/include/ObjectPool.hpp +++ b/include/ObjectPool.hpp @@ -9,7 +9,9 @@ class ObjectPool { public: - ObjectPool() : m_pool() + ObjectPool() + : m_pool() + , m_numberOfUsedObjects(0) { TRACE; } @@ -19,29 +21,62 @@ public: TRACE; } + void add(const T object) // throws CancelledException + { + TRACE; + m_pool.push(object); + } - T acquire() + + T acquire() // throws CancelledException { TRACE; - return m_pool.waitAndPop(); + T tmp = m_pool.waitAndPop(); + m_numberOfUsedObjects++; + return tmp; } - void release(const T object) + void release(T object) { TRACE; + if ( m_pool.cancelled() ) { + m_numberOfUsedObjects--; + return; + } + m_pool.push(object); + m_numberOfUsedObjects--; } - bool empty() const + void release(T* object) { TRACE; - return m_pool.empty(); + if ( m_pool.cancelled() ) { + m_numberOfUsedObjects--; + delete object; + return; + } + + m_pool.push(object); + m_numberOfUsedObjects--; } + void clear(T a) + { + TRACE; + m_pool.cancel(a); + } + + void clear(T* a) + { + TRACE; + m_pool.cancel(a); + } private: ConcurrentQueue m_pool; + int m_numberOfUsedObjects; }; #endif // OBJECT_POOL_HPP diff --git a/include/Thread.hpp b/include/Thread.hpp index bb9957b..592d212 100644 --- a/include/Thread.hpp +++ b/include/Thread.hpp @@ -17,17 +17,15 @@ public: void sendSignal( const int nSignal ) const; bool isRunning() const; -private: - - virtual void* run() = 0; - static void* threadStarter( void* pData ); - protected: bool m_isRunning; private: + virtual void* run() = 0; + static void* threadStarter( void* pData ); + pthread_t m_threadHandler; }; diff --git a/src/MysqlConnectionPool.cpp b/src/MysqlConnectionPool.cpp index 07259bb..315901f 100644 --- a/src/MysqlConnectionPool.cpp +++ b/src/MysqlConnectionPool.cpp @@ -27,12 +27,5 @@ void MysqlConnectionPool::create() MysqlClient *client = new MysqlClient ( m_host, m_user, m_passwd, m_db ); client->connect(); - release(client); -} - -void MysqlConnectionPool::clear() -{ - TRACE; - while ( !empty() ) - delete acquire(); + add(client); } diff --git a/src/ThreadPool.cpp b/src/ThreadPool.cpp index 5cbb74a..2df53f1 100644 --- a/src/ThreadPool.cpp +++ b/src/ThreadPool.cpp @@ -61,7 +61,8 @@ void ThreadPool::stop() (*it)->stop(); } - m_tasks.cancel(); + /// @todo solve this! +// m_tasks.cancel( ); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 56e6b87..b76249b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,20 +18,21 @@ if(CXXTEST_FOUND) generated_main.cpp Fixture.hpp - test_ArgParse.hpp - test_Common.hpp - test_ConditionalVariable.hpp - test_Multiton.hpp - test_Mutex.hpp - test_ScopedLock.hpp - test_Semaphore.hpp - test_Singleton_DCLP.hpp - test_Singleton_call_once.hpp - # test_Singleton.hpp Cannot test private member, Ficture.hpp loads it - test_Singleton_meyers.hpp - test_Thread.hpp - test_ThreadPool.hpp - # test_Timer.hpp Takes too much time&buggy +# test_ArgParse.hpp +# test_Common.hpp +# test_ConditionalVariable.hpp +# test_Multiton.hpp +# test_Mutex.hpp + test_ObjectPool.hpp +# test_ScopedLock.hpp +# test_Semaphore.hpp +# test_Singleton_DCLP.hpp +# test_Singleton_call_once.hpp +# # test_Singleton.hpp Cannot test private member, Ficture.hpp loads it +# test_Singleton_meyers.hpp +# test_Thread.hpp +# test_ThreadPool.hpp +# # test_Timer.hpp Takes too much time&buggy ) target_link_libraries(testCppUtils CppUtils gcov) endif() diff --git a/test/test_ObjectPool.hpp b/test/test_ObjectPool.hpp new file mode 100644 index 0000000..64a8b05 --- /dev/null +++ b/test/test_ObjectPool.hpp @@ -0,0 +1,130 @@ +#include + +#include "Common.hpp" +#include "Fixture.hpp" + +#include "ObjectPool.hpp" +#include "Thread.hpp" + +class TestObjectPool : public CxxTest::TestSuite +{ + +public: + + void testBasic( void ) + { + TEST_HEADER; + + ObjectPool op; + + int a(1); + op.add(a); + + TS_ASSERT_EQUALS( op.acquire(), a ); + } + + void testPointers( void ) + { + TEST_HEADER; + + ObjectPool op; + + int *a = new int(1); + int *b = new int(2); + op.add(a); + op.add(b); + + TS_ASSERT_EQUALS( op.acquire(), a ); + TS_ASSERT_EQUALS( op.acquire(), b ); + + delete a; + delete b; + } + + +private: + + class ObjecPoolUserThread : public Thread + { + public: + ObjecPoolUserThread( ObjectPool &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 &m_objectPool; + }; + +public: + + void testCompetingThreads( void ) + { + TEST_HEADER; + + ObjectPool op; + + ObjecPoolUserThread t1(op); + ObjecPoolUserThread t2(op); + + int *a = new int(27); + op.add(a); + + t1.start(); + t2.start(); + + t1.join(); + t2.join(); + + delete a; + } + + +public: + + void testCleanUp( void ) + { + TEST_HEADER; + + ObjectPool 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(); + } + +}; diff --git a/test/test_Semaphore.hpp b/test/test_Semaphore.hpp index 036be00..c8d39b0 100644 --- a/test/test_Semaphore.hpp +++ b/test/test_Semaphore.hpp @@ -106,7 +106,6 @@ public: t1->join(); t2->join(); - sleep(1); delete t1; delete t2; } From fdb6c5b7a1b8f14d0a51785b85f57ee080ccea6e Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Tue, 15 Nov 2011 15:06:45 +0100 Subject: [PATCH 5/5] Specialization of ConqurrentDeque::freeDeque and ObjectPool::release with Substitution failure is not an error (SFINAE) --- build/CMakeLists.txt | 2 +- ...oncurrentQueue.hpp => ConcurrentDeque.hpp} | 39 +++++++++++-------- include/MysqlConnectionPool.hpp | 1 - include/ObjectPool.hpp | 23 ++++++----- include/ThreadPool.hpp | 4 +- test/test_ObjectPool.hpp | 14 ++++--- 6 files changed, 45 insertions(+), 38 deletions(-) rename include/{ConcurrentQueue.hpp => ConcurrentDeque.hpp} (74%) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index ac6ba0b..f501db5 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -4,7 +4,7 @@ project (CPP_UTILS_LIB) set(CMAKE_CXX_COMPILER "/usr/lib/colorgcc/bin/g++") set (CXX_FLAGS "-Wall -Wextra -pedantic -Weffc++ -Wshadow " - "-ggdb -fprofile-arcs -ftest-coverage") + "-ggdb -fprofile-arcs -ftest-coverage -std=c++0x") add_definitions( ${CXX_FLAGS} ) include_directories (../include) diff --git a/include/ConcurrentQueue.hpp b/include/ConcurrentDeque.hpp similarity index 74% rename from include/ConcurrentQueue.hpp rename to include/ConcurrentDeque.hpp index 57e309e..a5908f7 100644 --- a/include/ConcurrentQueue.hpp +++ b/include/ConcurrentDeque.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "Mutex.hpp" #include "ConditionVariable.hpp" @@ -15,11 +16,11 @@ class CancelledException {}; template -class ConcurrentQueue +class ConcurrentDeque { public: - ConcurrentQueue() + ConcurrentDeque() : m_queue() , m_cancelled(false) , m_mutex() @@ -28,9 +29,10 @@ public: TRACE; } - ~ConcurrentQueue() + ~ConcurrentDeque() { TRACE; + freeDeque(); } @@ -81,29 +83,32 @@ public: return m_queue.empty(); } - - void cancel(T a) + void cancel() { TRACE; ScopedLock sl(m_mutex); m_cancelled = true; m_condVar.broadcast(); + freeDeque(); + } + + template + typename std::enable_if< std::is_pointer::value >::type + freeDeque() + { + TRACE; + typename std::deque::iterator it; + for ( it = m_queue.begin(); it != m_queue.end(); ++it ) + delete *it; m_queue.clear(); } - void cancel(T *a) + template + typename std::enable_if< !(std::is_pointer::value) >::type + freeDeque() { TRACE; - ScopedLock sl(m_mutex); - m_cancelled = true; - m_condVar.broadcast(); - - typename std::deque::iterator it; - for ( it = m_queue.begin(); it != m_queue.end(); ++it ) { - LOG( Logger::INFO, std::string("Deleting: ").append(*it).c_str() ); - delete *it; - } m_queue.clear(); } @@ -116,8 +121,8 @@ public: private: - ConcurrentQueue& operator=( const ConcurrentQueue& ); - ConcurrentQueue( const ConcurrentQueue& ); + ConcurrentDeque& operator=( const ConcurrentDeque& ); + ConcurrentDeque( const ConcurrentDeque& ); std::deque m_queue; bool m_cancelled; diff --git a/include/MysqlConnectionPool.hpp b/include/MysqlConnectionPool.hpp index 9b3f069..668b6ac 100644 --- a/include/MysqlConnectionPool.hpp +++ b/include/MysqlConnectionPool.hpp @@ -17,7 +17,6 @@ public: void create(); - /// @note Shall this be a specialized ObjectPool::clear? void clear(); private: diff --git a/include/ObjectPool.hpp b/include/ObjectPool.hpp index 8fdb63d..1fb092a 100644 --- a/include/ObjectPool.hpp +++ b/include/ObjectPool.hpp @@ -1,7 +1,7 @@ #ifndef OBJECT_POOL_HPP #define OBJECT_POOL_HPP -#include "ConcurrentQueue.hpp" +#include "ConcurrentDeque.hpp" #include "Logger.hpp" template @@ -36,11 +36,14 @@ public: return tmp; } - void release(T object) + template + typename std::enable_if< std::is_pointer::value >::type + release(T object) { TRACE; if ( m_pool.cancelled() ) { m_numberOfUsedObjects--; + delete object; return; } @@ -48,12 +51,13 @@ public: m_numberOfUsedObjects--; } - void release(T* object) + template + typename std::enable_if< !(std::is_pointer::value) >::type + release(T object) { TRACE; if ( m_pool.cancelled() ) { m_numberOfUsedObjects--; - delete object; return; } @@ -61,21 +65,16 @@ public: m_numberOfUsedObjects--; } - void clear(T a) + void clear() { TRACE; - m_pool.cancel(a); + m_pool.cancel(); } - void clear(T* a) - { - TRACE; - m_pool.cancel(a); - } private: - ConcurrentQueue m_pool; + ConcurrentDeque m_pool; int m_numberOfUsedObjects; }; diff --git a/include/ThreadPool.hpp b/include/ThreadPool.hpp index f88ac26..300b117 100644 --- a/include/ThreadPool.hpp +++ b/include/ThreadPool.hpp @@ -3,7 +3,7 @@ #include -#include "ConcurrentQueue.hpp" +#include "ConcurrentDeque.hpp" #include "Task.hpp" #include "Thread.hpp" #include "Mutex.hpp" @@ -32,7 +32,7 @@ class ThreadPool ThreadPool& operator=( const ThreadPool& ); std::vector m_threads; - ConcurrentQueue m_tasks; + ConcurrentDeque m_tasks; }; diff --git a/test/test_ObjectPool.hpp b/test/test_ObjectPool.hpp index 64a8b05..b0bb51a 100644 --- a/test/test_ObjectPool.hpp +++ b/test/test_ObjectPool.hpp @@ -34,11 +34,15 @@ public: op.add(a); op.add(b); - TS_ASSERT_EQUALS( op.acquire(), a ); - TS_ASSERT_EQUALS( op.acquire(), b ); + int *tmp_a = op.acquire(); + int *tmp_b = op.acquire(); + + TS_ASSERT_EQUALS( *tmp_a, *a ); + TS_ASSERT_EQUALS( *tmp_b, *b ); - delete a; - delete b; + // release will delete them + op.release(tmp_a); + op.release(tmp_b); } @@ -100,7 +104,7 @@ public: t1.join(); t2.join(); - delete a; + // no need to delete "a", dtor of the ConqurrentDeque takes care of it }