From 01cde4928db8479471b09b3bf4d6526d18371afc Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Wed, 2 Mar 2011 10:59:39 +0100 Subject: [PATCH] PThreadWrappers return with the retval of called pthread. Task became an interface. WorkerThread moved to test_ThreadPool.hpp. Thread has stop() and m_isRunning members. ThreadPool is now Task and Thread type independent. No more assertions in PThreadWrappers. Unittests refactored. test dir cleaned up. --- include/ConditionVariable.hpp | 6 +- include/Mutex.hpp | 4 +- include/Task.hpp | 9 +- include/Thread.hpp | 26 +-- include/ThreadPool.hpp | 15 +- include/WorkerThread.hpp | 26 --- src/ConditionVariable.cpp | 28 ++- src/Mutex.cpp | 20 +-- src/Task.cpp | 30 ---- src/Thread.cpp | 19 +- src/ThreadPool.cpp | 24 ++- src/WorkerThread.cpp | 40 ----- test/CMakeLists.txt | 10 +- test/main_Mutex.cpp | 41 ----- test/main_ScopedLock.cpp | 40 ----- test/main_concurrentQueue.cpp | 110 ------------ test/main_scopedLock.cpp | 85 --------- test/main_standalone_Mutex_ScopedLock.cpp | 206 ---------------------- test/main_thread.cpp | 87 --------- test/main_threadpool.cpp | 30 ---- test/test_ConditionalVariable.hpp | 19 ++ test/test_Mutex.hpp | 47 +++++ test/test_PThreadWrappers.hpp | 32 ++++ test/test_ScopedLock.hpp | 23 +++ test/test_Singelton.hpp | 5 - test/test_Thread.hpp | 116 ++++++++++++ test/test_ThreadPool.hpp | 97 ++++++++++ test/test_threadpool.hpp | 76 +++++++- test/valgrind.supp | 5 +- 29 files changed, 497 insertions(+), 779 deletions(-) delete mode 100644 include/WorkerThread.hpp delete mode 100644 src/Task.cpp delete mode 100644 src/WorkerThread.cpp delete mode 100644 test/main_Mutex.cpp delete mode 100644 test/main_ScopedLock.cpp delete mode 100644 test/main_concurrentQueue.cpp delete mode 100644 test/main_scopedLock.cpp delete mode 100644 test/main_standalone_Mutex_ScopedLock.cpp delete mode 100644 test/main_thread.cpp delete mode 100644 test/main_threadpool.cpp create mode 100644 test/test_ConditionalVariable.hpp create mode 100644 test/test_Mutex.hpp create mode 100644 test/test_PThreadWrappers.hpp create mode 100644 test/test_ScopedLock.hpp create mode 100644 test/test_Thread.hpp create mode 100644 test/test_ThreadPool.hpp diff --git a/include/ConditionVariable.hpp b/include/ConditionVariable.hpp index 8afabaa..fcef33c 100644 --- a/include/ConditionVariable.hpp +++ b/include/ConditionVariable.hpp @@ -12,9 +12,9 @@ public: ConditionVariable(Mutex& mutex); ~ConditionVariable(); - void wait(const int interval = 0); - void signal(); - void broadcast(); + int wait(const int interval = 0); + int signal(); + int broadcast(); private: diff --git a/include/Mutex.hpp b/include/Mutex.hpp index dca8f01..07a87f1 100644 --- a/include/Mutex.hpp +++ b/include/Mutex.hpp @@ -11,8 +11,8 @@ public: Mutex(int kind = PTHREAD_MUTEX_DEFAULT); ~Mutex(); - void lock(); - void unlock(); + int lock(); + int unlock(); bool tryLock(const int interval = 0); pthread_mutex_t* getPThreadMutex(); diff --git a/include/Task.hpp b/include/Task.hpp index e098a49..7f2e385 100644 --- a/include/Task.hpp +++ b/include/Task.hpp @@ -8,13 +8,10 @@ class Task public: - Task(); + virtual void run () = 0; + virtual bool isItStucked () const = 0; - void run (); - - bool isItStucked () const; - -private: +protected: time_t m_startedToRun; time_t m_timeOut; diff --git a/include/Thread.hpp b/include/Thread.hpp index ae3809a..0801772 100644 --- a/include/Thread.hpp +++ b/include/Thread.hpp @@ -6,24 +6,28 @@ class Thread { - public: +public: - Thread(); - virtual ~Thread(); + Thread(); + virtual ~Thread(); - void start(); - void* join() const; - void sendSignal( const int nSignal ) const; + void start(); + void* join() const; + void stop(); + void sendSignal( const int nSignal ) const; - private: +private: - virtual void* run() = 0; - static void* threadStarter( void* pData ); + virtual void* run() = 0; + static void* threadStarter( void* pData ); - private: +protected: - pthread_t m_nThread; + bool m_isRunning; +private: + + pthread_t m_threadHandler; }; diff --git a/include/ThreadPool.hpp b/include/ThreadPool.hpp index 91eb1ff..0c4b7f9 100644 --- a/include/ThreadPool.hpp +++ b/include/ThreadPool.hpp @@ -4,26 +4,25 @@ #include #include "ConcurrentQueue.hpp" -#include "WorkerThread.hpp" #include "Task.hpp" +#include "Thread.hpp" #include "Mutex.hpp" -class WorkerThread; - class ThreadPool { public: ThreadPool( const int threadNum ); - virtual ~ThreadPool(); - - void startWorkerThreads(); + ~ThreadPool(); - virtual void pushTask( Task* task ); + void pushTask( Task* task ); Task* popTask(); + void pushWorkerThread( Thread * thread); + void startWorkerThreads(); + void stop(); void join() const; @@ -33,7 +32,7 @@ class ThreadPool ThreadPool& operator=( const ThreadPool& ); int m_threadNum; - std::vector m_threads; + std::vector m_threads; ConcurrentQueue m_tasks; // Mutex m_mutex; }; diff --git a/include/WorkerThread.hpp b/include/WorkerThread.hpp deleted file mode 100644 index 1c31786..0000000 --- a/include/WorkerThread.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef WORKER_THREAD_HPP -#define WORKER_THREAD_HPP - -#include "Thread.hpp" -#include "ThreadPool.hpp" - -class ThreadPool; - -class WorkerThread : public Thread -{ - - public: - - WorkerThread( ThreadPool& tp ); - void stop(); - - private: - - void* run(); - - ThreadPool& m_tp; - bool m_isRunning; - -}; - -#endif // WORKER_THREAD_HPP diff --git a/src/ConditionVariable.cpp b/src/ConditionVariable.cpp index cc775b8..c64ca85 100644 --- a/src/ConditionVariable.cpp +++ b/src/ConditionVariable.cpp @@ -8,26 +8,23 @@ ConditionVariable::ConditionVariable(Mutex& mutex) : m_mutex(mutex) { TRACE(this); - int ret = pthread_cond_init( &m_condVar, 0 ); - assert( ret == 0); + pthread_cond_init( &m_condVar, 0 ); } ConditionVariable::~ConditionVariable() { TRACE(this); - int ret = pthread_cond_destroy( &m_condVar ); - assert( ret == 0); + pthread_cond_destroy( &m_condVar ); } -void ConditionVariable::wait(const int interval) +int ConditionVariable::wait(const int interval) { TRACE(this); if ( interval == 0 ) { - int ret = pthread_cond_wait( &m_condVar, + return pthread_cond_wait( &m_condVar, m_mutex.getPThreadMutex() ); - assert( ret == 0); } else { timespec abs_time; clock_gettime ( CLOCK_REALTIME, &abs_time ); @@ -36,23 +33,20 @@ void ConditionVariable::wait(const int interval) abs_time.tv_nsec -= 1000000000; abs_time.tv_sec += 1; } - int ret = pthread_cond_timedwait( &m_condVar, - m_mutex.getPThreadMutex(), - &abs_time ); - assert( ret == 0); + return pthread_cond_timedwait( &m_condVar, + m_mutex.getPThreadMutex(), + &abs_time ); } } -void ConditionVariable::signal() +int ConditionVariable::signal() { TRACE(this); - int ret = pthread_cond_signal( &m_condVar ); - assert( ret == 0); + return pthread_cond_signal( &m_condVar ); } -void ConditionVariable::broadcast() +int ConditionVariable::broadcast() { TRACE(this); - int ret = pthread_cond_broadcast( &m_condVar ); - assert( ret == 0); + return pthread_cond_broadcast( &m_condVar ); } diff --git a/src/Mutex.cpp b/src/Mutex.cpp index 329cb0d..75b1b7a 100644 --- a/src/Mutex.cpp +++ b/src/Mutex.cpp @@ -1,47 +1,41 @@ #include "Mutex.hpp" #include "Common.hpp" -#include #include Mutex::Mutex(int kind) { TRACE(this); - int ret; if ( kind == PTHREAD_MUTEX_DEFAULT ) { - ret = pthread_mutex_init( &m_mutex, 0 ); + pthread_mutex_init( &m_mutex, 0 ); } else { pthread_mutexattr_t attr; pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, kind ); - ret = pthread_mutex_init( &m_mutex, &attr ); + pthread_mutex_init( &m_mutex, &attr ); } - assert( ret == 0 ); } Mutex::~Mutex() { TRACE(this); - int ret = pthread_mutex_destroy ( &m_mutex ); - assert( ret == 0); + pthread_mutex_destroy ( &m_mutex ); } -void Mutex::lock() +int Mutex::lock() { TRACE(this); - int ret = pthread_mutex_lock( &m_mutex ); - assert( ret == 0); + return pthread_mutex_lock( &m_mutex ); } -void Mutex::unlock() +int Mutex::unlock() { TRACE(this); - int ret = pthread_mutex_unlock ( &m_mutex ); - assert( ret == 0); + return pthread_mutex_unlock ( &m_mutex ); } diff --git a/src/Task.cpp b/src/Task.cpp deleted file mode 100644 index bed98c7..0000000 --- a/src/Task.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "Task.hpp" - -#include - -#include "Common.hpp" - -Task::Task() : m_timeOut(5) -{ - TRACE(this); -} - - -void Task::run() -{ - TRACE(this); - m_startedToRun = time(NULL); - - std::cout << "I'm a task..." << std::endl; - - // other stuff - - m_startedToRun = 0; -} - - -bool Task::isItStucked () const -{ - TRACE(this); - return ( m_startedToRun + m_timeOut < time(NULL) ); -} diff --git a/src/Thread.cpp b/src/Thread.cpp index 08e79c0..8140d3d 100644 --- a/src/Thread.cpp +++ b/src/Thread.cpp @@ -4,7 +4,10 @@ #include #include -Thread::Thread() : m_nThread( 0 ) +Thread::Thread() + : m_isRunning(false) + , m_threadHandler( 0 ) + { TRACE(this); } @@ -19,7 +22,8 @@ Thread::~Thread() void Thread::start() { TRACE(this); - pthread_create( &m_nThread, NULL, threadStarter, ( void* )this ); + m_isRunning = true; + pthread_create( &m_threadHandler, NULL, threadStarter, ( void* )this ); } @@ -27,15 +31,22 @@ void* Thread::join() const { TRACE(this); void* retVal; - pthread_join( m_nThread, &retVal ); + pthread_join( m_threadHandler, &retVal ); return retVal; } +void Thread::stop() +{ + TRACE(this); + m_isRunning = false; +} + + void Thread::sendSignal( const int nSignal ) const { TRACE(this); - pthread_kill( m_nThread, nSignal ); + pthread_kill( m_threadHandler, nSignal ); } diff --git a/src/ThreadPool.cpp b/src/ThreadPool.cpp index a4e6876..f887b5b 100644 --- a/src/ThreadPool.cpp +++ b/src/ThreadPool.cpp @@ -2,7 +2,7 @@ #include "Common.hpp" -ThreadPool::ThreadPool( const int threadNum ) : m_threadNum( threadNum ) +ThreadPool::ThreadPool() { TRACE(this); } @@ -10,7 +10,7 @@ ThreadPool::ThreadPool( const int threadNum ) : m_threadNum( threadNum ) ThreadPool::~ThreadPool() { TRACE(this); - std::vector::iterator it; + std::vector::iterator it; for( it = m_threads.begin() ; it != m_threads.end(); it++ ) { delete (*it); @@ -24,6 +24,7 @@ void ThreadPool::pushTask( Task* task ) m_tasks.push(task); } + Task* ThreadPool::popTask() { TRACE(this); @@ -31,21 +32,28 @@ Task* ThreadPool::popTask() } +void ThreadPool::pushWorkerThread( Thread * thread) +{ + TRACE(this); + m_threads.push_back( thread ); +} + + void ThreadPool::startWorkerThreads() { TRACE(this); - for( int i = 0; i::iterator it; + for( it = m_threads.begin() ; it != m_threads.end(); it++ ) { - WorkerThread* t = new WorkerThread ( *this ); - m_threads.push_back( t ); - t->start(); + (*it)->start(); } + } void ThreadPool::stop() { TRACE(this); - std::vector::iterator it; + std::vector::iterator it; for( it = m_threads.begin() ; it != m_threads.end(); it++ ) { (*it)->stop(); @@ -58,7 +66,7 @@ void ThreadPool::stop() void ThreadPool::join() const { TRACE(this); - std::vector::const_iterator it; + std::vector::const_iterator it; for( it = m_threads.begin() ; it != m_threads.end(); it++ ) { (*it)->join(); diff --git a/src/WorkerThread.cpp b/src/WorkerThread.cpp deleted file mode 100644 index 9fb5e72..0000000 --- a/src/WorkerThread.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "WorkerThread.hpp" -#include "Task.hpp" -#include "Common.hpp" - - -WorkerThread::WorkerThread( ThreadPool& tp ) - : m_tp(tp) - , m_isRunning(true) -{ - TRACE(this); -} - - -void WorkerThread::stop() -{ - TRACE(this); - m_isRunning = false; -} - - -void* WorkerThread::run() -{ - TRACE(this); - while ( m_isRunning ) - { - Task* task(0); - try { - task = m_tp.popTask(); - task->run(); - delete task; - } catch (CancelledException) { - std::cout << "Now I die." << std::endl; - } - - } - - return 0; -} - - diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bc9357b..31994b7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,9 +6,15 @@ if(CXXTEST_FOUND) set(CXXTEST_USE_PERL TRUE) include_directories(${CXXTEST_INCLUDE_DIR} ../include) enable_testing() -CXXTEST_ADD_TEST(test generated_main.cpp -test_threadpool.hpp +CXXTEST_ADD_TEST(test +generated_main.cpp + test_Singelton.hpp +test_Mutex.hpp +test_ScopedLock.hpp +test_ConditionalVariable.hpp +test_Thread.hpp +test_ThreadPool.hpp ) target_link_libraries(test CppUtils gcov) endif() diff --git a/test/main_Mutex.cpp b/test/main_Mutex.cpp deleted file mode 100644 index 1b4f560..0000000 --- a/test/main_Mutex.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// g++ -Wall -Wextra src/*.cpp test/main_Mutex.cpp -Iinclude -lpthread -lrt - -#include -#include - -#include "Mutex.hpp" - -Mutex m; -int counter = 0; - -void *functionC( void* params ) -{ - m.lock(); - counter++; - std::cout << "Counter value: " << counter << std::endl; - m.unlock(); - return 0; -} - - -int main() -{ - pthread_t thread1, thread2; - - pthread_create( &thread1, 0, &functionC, 0 ); - pthread_create( &thread2, 0, &functionC, 0 ); - - pthread_join( thread1, 0 ); - pthread_join( thread2, 0 ); - - Mutex m2(PTHREAD_MUTEX_ERRORCHECK); - - m2.lock(); - m2.unlock(); - - m2.unlock(); - m2.unlock(); - - return 0; -} - diff --git a/test/main_ScopedLock.cpp b/test/main_ScopedLock.cpp deleted file mode 100644 index 9f91c70..0000000 --- a/test/main_ScopedLock.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// g++ -Wall -Wextra src/*.cpp test/main_Mutex.cpp -Iinclude -lpthread -lrt - - -#include "ScopedLock.hpp" -#include "Mutex.hpp" -#include "Common.hpp" - -#include - -class User -{ -public: - User() : m_mutex() { - TRACE(this); - } - ~User() { - TRACE(this); - } - void fv() { - TRACE(this); - ScopedLock sl(&m_mutex); - throw std::logic_error("whoops"); - } -private: - Mutex m_mutex; -}; - -int main() -{ - User u; - - try { - u.fv(); - } catch (std::logic_error ex) { - std::cout << "std::logicexception: " << ex.what() << std::endl; - } - - return 0; -} - diff --git a/test/main_concurrentQueue.cpp b/test/main_concurrentQueue.cpp deleted file mode 100644 index f9dce75..0000000 --- a/test/main_concurrentQueue.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include - -#include "../ConcurrentQueue.hpp" -#include "../Thread.hpp" - -#define TRACE std::cout << __FILE__ << " @ " << __PRETTY_FUNCTION__ << ":" << __LINE__ << std::endl; - -class WaitingThread : public Thread -{ - - public: - - WaitingThread (ConcurrentQueue& cq) - : m_isRunning( true ), - m_cq(cq) - { - TRACE - } - - ~WaitingThread() - { - TRACE - } - - void stop () - { - TRACE - m_isRunning = false; - } - - private: - - void* run () - { - TRACE - while ( m_isRunning ) - { - std::cout << "waiting..." << std::endl; - int retval = m_cq.waitAndPop(); - std::cout << "waiting...ENDED! Got retval: " << retval << std::endl; - } - - return 0; - } - - bool m_isRunning; - ConcurrentQueue& m_cq; -}; - -class fake_type -{ - -public: - - fake_type(int i) : m_int(i) - { - TRACE - } - - ~fake_type() - { - TRACE - } - - fake_type( const fake_type& m) - { - TRACE - m_int = m.m_int; - } - - fake_type& operator=( const fake_type& m) - { - TRACE - m_int = m.m_int; - return *this; - } - -private: - int m_int; -}; - - -int main() -{ - ConcurrentQueue cq1; - cq1.push(fake_type(7)); - - fake_type m = cq1.waitAndPop(); - - // other case - - ConcurrentQueue cq2; - cq2.push(7); - cq2.push(13); - - WaitingThread* wt1 = new WaitingThread(cq2); - wt1->start(); - - sleep(2); - - cq2.push(34); - - sleep(5); - - wt1->stop(); - - sleep(5); - - return 0; -} diff --git a/test/main_scopedLock.cpp b/test/main_scopedLock.cpp deleted file mode 100644 index 5dde860..0000000 --- a/test/main_scopedLock.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include - -#include -pthread_mutex_t p_mutex; - -// #include -// boost::mutex b_mutex; - -#define TRACE std::cout << __FILE__ << " @ " << __PRETTY_FUNCTION__ << ":" << __LINE__ << std::endl; - - -class ScopedLock -{ - -public: - - ScopedLock(pthread_mutex_t & mutex) : m_mutex(mutex) - { - TRACE; - pthread_mutex_lock( &m_mutex ); - } - - - ~ScopedLock(void ) - { - TRACE; - pthread_mutex_unlock( &m_mutex ); - } - -private: - - pthread_mutex_t& m_mutex; - -}; - - -void fv () -{ - ScopedLock sl(p_mutex); - - throw std::logic_error("p_thread stuff"); -} - - -// void fv2 () -// { -// boost::mutex::scoped_lock lock(&b_mutex); -// -// throw std::logic_error("boost_thread stuff"); -// } - - -int main() -{ - pthread_mutex_init( &p_mutex, NULL ); - try { - fv(); - } catch (...) { - TRACE; - - if (pthread_mutex_trylock( &p_mutex) == 0 ) { -// std::cout << "pthread mutex is OK, unlocked " << std::endl; -// pthread_mutex_unlock( &p_mutex ); - } else { -// std::cout << "pthread mutex is STILL LOCKED!" << std::endl; - } - } - pthread_mutex_destroy( &p_mutex ); - - -// try { -// fv2(); -// } catch (...) { -// TRACE; -// if ( b_mutex.try_lock() == true ) { -// std::cout << "boost mutex is OK, unlocked " << std::endl; -// b_mutex.unlock(); -// } else { -// std::cout << "boost mutex is STILL LOCKED!" << std::endl; -// } -// } - - return 0; -} diff --git a/test/main_standalone_Mutex_ScopedLock.cpp b/test/main_standalone_Mutex_ScopedLock.cpp deleted file mode 100644 index 1f17e0c..0000000 --- a/test/main_standalone_Mutex_ScopedLock.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include - -#ifndef NOTRACE - #define TRACE(x) std::cout << x << " " << __PRETTY_FUNCTION__ << \ - " : " << __LINE__ << std::endl - -#else - /// @todo Get rid of the "warning: statement has no effect" compiler msgs - #define TRACE(x) "" -#endif - - -#include -#include - -#include -#include - -class Mutex -{ -public: - - Mutex() { - TRACE(this); - int ret = pthread_mutex_init( &m_mutex, 0 ); -// assert( ret == 0 ); - } - ~Mutex() { - TRACE(this); - int ret = pthread_mutex_destroy ( &m_mutex ); -// assert( ret == 0 ); - } - void lock() { - TRACE(this); - int ret = pthread_mutex_lock( &m_mutex ); -// assert( ret == 0 ); - } - void unlock() { - TRACE(this); - int ret = pthread_mutex_unlock( &m_mutex ); -// assert( ret == 0 ); - } -// private: - Mutex(const Mutex& m){ - TRACE(this); - } - Mutex& operator=(const Mutex& m) { - TRACE(this); - return *this; - } - - int tryLock() { - TRACE(this); -// return pthread_mutex_trylock(&m_mutex); - int interval = 1; - - timespec abs_time; - clock_gettime ( CLOCK_REALTIME, &abs_time ); - abs_time.tv_nsec += interval * 1000000; - if ( abs_time.tv_nsec >= 1000000000 ) { - abs_time.tv_nsec -= 1000000000; - abs_time.tv_sec += 1; - } - return pthread_mutex_timedlock ( &m_mutex, &abs_time ); - } - -private: - pthread_mutex_t m_mutex; -}; - - -class BadScopedLock -{ -public: - - BadScopedLock(Mutex& m) - : m_mutex(m) /// @note cctor called! - { - TRACE(this); - m_mutex.lock(); - } - ~BadScopedLock() { - TRACE(this); - m_mutex.unlock(); - } - -private: - BadScopedLock(const BadScopedLock&); - BadScopedLock& operator=(const BadScopedLock&); - - Mutex& m_mutex; -}; - -class UnluckyUser -{ -public: - UnluckyUser() : m_mutex() { - TRACE(this); - } - ~UnluckyUser() { - TRACE(this); - } - void fv() { - TRACE(this); - BadScopedLock sl(m_mutex); - throw std::logic_error("whoops"); - } - int tryLock() { - TRACE(this); - return m_mutex.tryLock(); - } -private: - Mutex m_mutex; -}; - -// class GoodScopedLock -// { -// public: -// -// GoodScopedLock(Mutex* m) : m_mutex(m) -// { -// TRACE(this); -// m_mutex->lock(); -// } -// ~GoodScopedLock() { -// TRACE(this); -// m_mutex->unlock(); -// } -// -// private: -// GoodScopedLock(const GoodScopedLock&); -// GoodScopedLock& operator=(const GoodScopedLock&); -// -// Mutex* m_mutex; -// }; -/* -class LuckyUser -{ -public: - LuckyUser() : m_mutex() { - TRACE(this); - } - ~LuckyUser() { - TRACE(this); - } - void fv() { - TRACE(this); - GoodScopedLock sl(&m_mutex); - throw std::logic_error("whoops"); - } - int tryLock() { - TRACE(this); - return m_mutex.tryLock(); - } -private: - Mutex m_mutex; -};*/ - - -int main() -{ - TRACE("main begin"); -// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -// // pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; -// std::cout << "bla1" << std::endl; -// std::cout << pthread_mutex_unlock( &mutex )<< std::endl; -// std::cout << pthread_mutex_trylock( &mutex ) << std::endl; -// std::cout << "bla2" << std::endl; -// // std::cout << pthread_mutex_unlock( &mutex ) << std::endl; -// -// std::cout << "bla3" << std::endl; -// -// std::cout << pthread_mutex_lock( &mutex ) << std::endl; -// std::cout << pthread_mutex_trylock( &mutex ) << std::endl; -// // std::cout << pthread_mutex_lock( &mutex ) << std::endl; - - UnluckyUser u; - try { - u.fv(); - } catch (std::logic_error ex) { - std::cout << "std::logicexception: " << ex.what() << std::endl; - if (u.tryLock() == 0) { - std::cout << "UnluckyUser: Ok, mutex is unlocked" << std::endl; - } else { - std::cout << "UnluckyUser: Failed, mutex is still locked" << std::endl; - } - } - -// TRACE("main middle"); -// -// LuckyUser u2; -// try { -// u2.fv(); -// } catch (std::logic_error ex) { -// std::cout << "std::logicexception: " << ex.what() << std::endl; -// if (u2.tryLock() == 0) { -// std::cout << "LuckyUser: Ok, mutex is unlocked" << std::endl; -// } else { -// std::cout << "LuckyUser: Failed, mutex is still locked" << std::endl; -// } -// } - - - TRACE("main end"); - return 0; -} diff --git a/test/main_thread.cpp b/test/main_thread.cpp deleted file mode 100644 index 5783fcb..0000000 --- a/test/main_thread.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include - -#include // signal to thread -#include // malloc -// #include - -#include "Thread.hpp" -#include "Common.hpp" - -class ThreadClass : public Thread -{ -public: - - ~ThreadClass() { TRACE(this); } - ThreadClass() { TRACE(this); } - -private: - - void* run( void ) { - TRACE(this); - - void *retval = malloc(sizeof(int)); - *((int*)retval) = 14; - return retval; - return 0; - } -}; - -class ThreadClassWithSignal : public Thread -{ -public: - - ~ThreadClassWithSignal() { - TRACE(this); - } - ThreadClassWithSignal() { - TRACE(this); - signal(SIGINT, signal_handler); - } - -private: - - void* run( void ) { - TRACE(this); - - void *retval = malloc(sizeof(int)); - *((int*)retval) = 14; - return retval; - return 0; - } - - void static signal_handler(int sig) - { - TRACE("ThreadClassWithSignal::signal_handler"); - if (sig==SIGINT) { - TRACE("signal_handler got SIGINT"); - pthread_exit(0); - } - } -}; - - -int main() -{ - TRACE("main start"); - - ThreadClass *m = new ThreadClass; - m->start(); - - void *retVal = m->join(); - std::cout << "got retVal: " << *((int*)retVal) << std::endl; - free(retVal); - delete m; - - ThreadClass *m2 = new ThreadClass; - m2->start(); - m2->sendSignal(SIGINT); - - sleep(3); - - std::cout << "after sendSignal the:" << m2 < - -#include -#include -#include - -#include "ThreadPool.hpp" -#include "Task.hpp" -#include "Common.hpp" - - -int main() -{ - TRACE("Main start"); - - ThreadPool* tp = new ThreadPool(5); - tp->startWorkerThreads(); - - Task* t1 = new Task(); - tp->pushTask(t1); - - sleep(2); - - tp->stop(); - tp->join(); - delete tp; - - TRACE("Main end"); - return 0; -} diff --git a/test/test_ConditionalVariable.hpp b/test/test_ConditionalVariable.hpp new file mode 100644 index 0000000..9eab96b --- /dev/null +++ b/test/test_ConditionalVariable.hpp @@ -0,0 +1,19 @@ +#include + +#include "Mutex.hpp" +#include "ConditionVariable.hpp" + + +class TestConditionVariable : public CxxTest::TestSuite +{ + + +public: + + void testBasic( void ) + { + Mutex m; + ConditionVariable c(m); + } + +}; diff --git a/test/test_Mutex.hpp b/test/test_Mutex.hpp new file mode 100644 index 0000000..0d61dc0 --- /dev/null +++ b/test/test_Mutex.hpp @@ -0,0 +1,47 @@ +#include + +#include "Common.hpp" +#include "Mutex.hpp" + +#include // EDEADLK, EPERM + +class TestMutex : public CxxTest::TestSuite +{ + + +public: + + void testBasic( void ) + { + Mutex m; + TS_ASSERT_EQUALS ( m.lock() , 0 ); + // TS_ASSERT_EQUALS ( m.lock() , 0 ); that would be a deadlock + TS_ASSERT_EQUALS ( m.tryLock(0), false ); + TS_ASSERT_EQUALS ( m.tryLock(2), false ); + TS_ASSERT_EQUALS ( m.unlock() , 0 ); + TS_ASSERT_EQUALS ( m.unlock() , 0 ); + } + + void testErrorCheck( void ) + { + Mutex m(PTHREAD_MUTEX_ERRORCHECK); + TS_ASSERT_EQUALS ( m.lock() , 0 ); + TS_ASSERT_EQUALS ( m.lock(), EDEADLK ); + + TS_ASSERT_EQUALS ( m.unlock() , 0 ); + TS_ASSERT_EQUALS ( m.unlock() , EPERM ); + } + + void testRecursive( void ) + { + Mutex m(PTHREAD_MUTEX_RECURSIVE); + TS_ASSERT_EQUALS ( m.lock() , 0 ); + TS_ASSERT_EQUALS ( m.lock() , 0 ); + + TS_ASSERT_EQUALS ( m.unlock() , 0 ); + TS_ASSERT_EQUALS ( m.unlock() , 0 ); + TS_ASSERT_EQUALS ( m.unlock() , EPERM ); + } + + +}; diff --git a/test/test_PThreadWrappers.hpp b/test/test_PThreadWrappers.hpp new file mode 100644 index 0000000..99156c2 --- /dev/null +++ b/test/test_PThreadWrappers.hpp @@ -0,0 +1,32 @@ +#include + +#define private public // need to reach private variables + +#include "Common.hpp" +#include "Mutex.hpp" + +class TestPThreadWrappers : public CxxTest::TestSuite +{ + + +public: + + void testMutexBasic( void ) + { + Mutex m; + m.lock(); + TS_ASSERT_EQUALS ( m.tryLock(0), 0 ); + m.unlock(); + } + + void testMutexCreate( void ) + { + Mutex m(PTHREAD_MUTEX_ERRORCHECK); + m.lock(); + TS_ASSERT_EQUALS ( m.lock(), 1 ); + + m.unlock(); + } + + +}; diff --git a/test/test_ScopedLock.hpp b/test/test_ScopedLock.hpp new file mode 100644 index 0000000..a469c49 --- /dev/null +++ b/test/test_ScopedLock.hpp @@ -0,0 +1,23 @@ +#include + +#include "ScopedLock.hpp" + + +class TestScopedLock : public CxxTest::TestSuite +{ + + +public: + + void testBasic( void ) + { + Mutex m; + + { + ScopedLock sl(m); + TS_ASSERT_EQUALS ( m.tryLock(0), false ); + } + TS_ASSERT_EQUALS ( m.tryLock(0), true ); + } + +}; diff --git a/test/test_Singelton.hpp b/test/test_Singelton.hpp index 2914de9..0e02f3b 100644 --- a/test/test_Singelton.hpp +++ b/test/test_Singelton.hpp @@ -1,8 +1,3 @@ - - -// gpp ./generated_main.cpp ../src/*.cpp -I../include -lpthread -lrt - - #include #define private public // need to reach Singleton's private m_instance diff --git a/test/test_Thread.hpp b/test/test_Thread.hpp new file mode 100644 index 0000000..d324a75 --- /dev/null +++ b/test/test_Thread.hpp @@ -0,0 +1,116 @@ +#include + +#include "Thread.hpp" +#include "Common.hpp" +#include "Mutex.hpp" +#include "ScopedLock.hpp" + +#include // malloc +#include // SIGINT + + +class TestThread : public CxxTest::TestSuite +{ +private: + + class ThreadClass : public Thread + { + public: + + ThreadClass() { TRACE(this); } + ~ThreadClass() { TRACE(this); } + + + private: + + ThreadClass(const ThreadClass&) { TRACE(this); } + ThreadClass& operator=(const ThreadClass&) { TRACE(this); return*this; } + + void* run( void ) { + TRACE(this); + + void* retVal = malloc(sizeof(int)); + *((int*)retVal) = 14; + return retVal; + } + }; + +public: + + void testBasic( void ) + { + ThreadClass *m = new ThreadClass; + m->start(); + + void *retVal = m->join(); + TS_ASSERT_EQUALS ( *((int*)retVal) , 14 ); + free(retVal); + delete m; + } + +/** + * @note send a signal to a thread + */ + +private: + + class ThreadClassWithSignal : public Thread + { + public: + + ThreadClassWithSignal() { + TRACE(this); + signal(SIGINT, signal_handler); + } + ~ThreadClassWithSignal() { + TRACE(this); + } + + + private: + + ThreadClassWithSignal(const ThreadClassWithSignal&) { TRACE(this); } + ThreadClassWithSignal& operator=(const ThreadClassWithSignal&) { TRACE(this); return*this; } + + void* run( void ) { + TRACE(this); + + /** @note the function will get stopped before it finishes sleeping + * If signal arrives after malloc, it will be a memory leak. + */ + sleep(32); + + void* retVal = malloc(sizeof(int)); + *((int*)retVal) = 15; + return retVal; + } + + static void signal_handler(int sig) + { + TRACE("ThreadClassWithSignal::signal_handler"); + if (sig==SIGINT) { + TRACE("signal_handler got SIGINT"); + + void* retVal = malloc(sizeof(int)); + *((int*)retVal) = 16; + pthread_exit(retVal); + } + } + }; + +public: + + void testSignalSend( void ) + { + ThreadClassWithSignal *m2 = new ThreadClassWithSignal; + m2->start(); + m2->sendSignal(SIGINT); + + sleep(3); + void *retVal = m2->join(); + TS_ASSERT_EQUALS ( *((int*)retVal) , 16 ); + free(retVal); + delete m2; + } + +}; diff --git a/test/test_ThreadPool.hpp b/test/test_ThreadPool.hpp new file mode 100644 index 0000000..c322505 --- /dev/null +++ b/test/test_ThreadPool.hpp @@ -0,0 +1,97 @@ +#include + +// #include // time + +#include "Task.hpp" +#include "Thread.hpp" +#include "ThreadPool.hpp" +#include "Common.hpp" + + + + +class TestThreadPoolSuite : public CxxTest::TestSuite +{ + + class DummyTask : public Task + { + + public: + + DummyTask() { m_timeOut = 5; TRACE(this); } + + void run() + { + TRACE(this); + m_startedToRun = time(NULL); + TRACE("I'm a task..."); + m_startedToRun = 0; + } + + bool isItStucked () const + { + TRACE(this); + return ( m_startedToRun + m_timeOut < time(NULL) ); + } + }; + + class WorkerThread : public Thread + { + + public: + + WorkerThread( ThreadPool& tp ) + : m_tp(tp) + { + TRACE(this); + } + + private: + + void* run() + { + TRACE(this); + while ( m_isRunning ) + { + Task* task(0); + try { + task = m_tp.popTask(); + task->run(); + delete task; + } catch (CancelledException) { + TRACE("Now I die."); + } + } + return 0; + } + + ThreadPool& m_tp; + }; + + +public: + + void testBasic() + { + ThreadPool* tp = new ThreadPool(); + + Thread* wt1 = new WorkerThread(*tp); + Thread* wt2 = new WorkerThread(*tp); + Thread* wt3 = new WorkerThread(*tp); + tp->pushWorkerThread(wt1); + tp->pushWorkerThread(wt2); + tp->pushWorkerThread(wt3); + tp->startWorkerThreads(); + + Task* t1 = new DummyTask(); + tp->pushTask(t1); + Task* t2 = new DummyTask(); + tp->pushTask(t2); + + sleep(2); + + tp->stop(); + tp->join(); + delete tp; + } +}; diff --git a/test/test_threadpool.hpp b/test/test_threadpool.hpp index ba37009..5da281d 100644 --- a/test/test_threadpool.hpp +++ b/test/test_threadpool.hpp @@ -1,13 +1,79 @@ #include -#include "ThreadPool.hpp" +// #include // time + #include "Task.hpp" +#include "Thread.hpp" +#include "ThreadPool.hpp" #include "Common.hpp" + + class TestThreadPoolSuite : public CxxTest::TestSuite { + class DummyTask : public Task + { + + public: + + DummyTask() { m_timeOut = 5; TRACE(this); } + + void run() + { + TRACE(this); + m_startedToRun = time(NULL); + std::cout << "I'm a task..." << std::endl; + // other stuff + m_startedToRun = 0; + } + + bool isItStucked () const + { + TRACE(this); + return ( m_startedToRun + m_timeOut < time(NULL) ); + } + }; + + class WorkerThread : public Thread + { + + public: + + WorkerThread( ThreadPool& tp ) + : m_tp(tp) + { + TRACE(this); + } + + private: + + void* run() + { + TRACE(this); + while ( m_isRunning ) + { + Task* task(0); + try { + task = m_tp.popTask(); + task->run(); + delete task; + } catch (CancelledException) { + std::cout << "Now I die." << std::endl; + } + + } + + return 0; + } + + ThreadPool& m_tp; + bool m_isRunning; + + }; + + public: void testBasic() @@ -15,9 +81,15 @@ public: TRACE("testBasic begin"); ThreadPool* tp = new ThreadPool(5); + Thread* wt1 = new WorkerThread(*tp); +// Thread* wt2 = new WorkerThread(*tp); +// Thread* wt3 = new WorkerThread(*tp); + tp->pushWorkerThread(wt1); +// tp->pushWorkerThread(wt2); +// tp->pushWorkerThread(wt3); tp->startWorkerThreads(); - Task* t1 = new Task(); + Task* t1 = new DummyTask(); tp->pushTask(t1); sleep(2); diff --git a/test/valgrind.supp b/test/valgrind.supp index 21d6bfc..4161356 100644 --- a/test/valgrind.supp +++ b/test/valgrind.supp @@ -44,7 +44,6 @@ fun:calloc fun:_dl_allocate_tls fun:pthread_create@@GLIBC_2.2.5 - fun:_ZN6Thread5startEv - fun:_ZN10ThreadPool18startWorkerThreadsEv - fun:main } + +