From a87978afef075f715515c41aabb20f5f60e03c99 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sat, 19 Mar 2011 15:02:55 +0100 Subject: [PATCH] new class: Semaphore, smal fixes --- .gitignore | 1 + include/Common.hpp | 2 +- include/ConcurrentQueue.hpp | 12 ++--- include/Semaphore.hpp | 28 ++++++++++ src/ConditionVariable.cpp | 6 ++- src/Semaphore.cpp | 54 +++++++++++++++++++ test/CMakeLists.txt | 1 + test/run_test.sh | 2 +- test/test_Semaphore.hpp | 105 ++++++++++++++++++++++++++++++++++++ test/test_Thread.hpp | 9 ++-- 10 files changed, 208 insertions(+), 12 deletions(-) create mode 100644 include/Semaphore.hpp create mode 100644 src/Semaphore.cpp create mode 100644 test/test_Semaphore.hpp diff --git a/.gitignore b/.gitignore index 7f83c5f..6b19832 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.a *.so */a.out +test.out */cov */lcov.info */lcov2.info diff --git a/include/Common.hpp b/include/Common.hpp index 7d7a7a6..17e857b 100644 --- a/include/Common.hpp +++ b/include/Common.hpp @@ -29,7 +29,7 @@ inline timespec intIntervalTotimespec(const int & interval) abs_time.tv_sec += 1; } return abs_time; -}; +} #endif // COMMON_HPP diff --git a/include/ConcurrentQueue.hpp b/include/ConcurrentQueue.hpp index e2f763c..dffe3a3 100644 --- a/include/ConcurrentQueue.hpp +++ b/include/ConcurrentQueue.hpp @@ -21,7 +21,7 @@ class ConcurrentQueue { ConcurrentQueue() : m_cancelled(false) , m_mutex() - , m_condition(m_mutex) + , m_condVar(m_mutex) { TRACE(this); } @@ -38,7 +38,7 @@ class ConcurrentQueue { ScopedLock sl(m_mutex); if (m_cancelled) throw CancelledException(); m_queue.push( task ); - m_condition.signal(); + m_condVar.signal(); } @@ -61,7 +61,7 @@ class ConcurrentQueue { ScopedLock sl(m_mutex); while ( m_queue.empty() and not m_cancelled) { - m_condition.wait(); + m_condVar.wait(); } if (m_cancelled) throw CancelledException(); @@ -85,7 +85,7 @@ class ConcurrentQueue { TRACE(this); ScopedLock sl(m_mutex); m_cancelled = true; - m_condition.broadcast(); + m_condVar.broadcast(); } private: @@ -95,8 +95,8 @@ class ConcurrentQueue { std::queue m_queue; bool m_cancelled; - Mutex m_mutex; - ConditionVariable m_condition; + mutable Mutex m_mutex; + ConditionVariable m_condVar; }; diff --git a/include/Semaphore.hpp b/include/Semaphore.hpp new file mode 100644 index 0000000..9a85242 --- /dev/null +++ b/include/Semaphore.hpp @@ -0,0 +1,28 @@ +#ifndef SEMAPHORE_HPP +#define SEMAPHORE_HPP + +#include "Mutex.hpp" +#include "ConditionVariable.hpp" + + +class Semaphore +{ + +public: + + Semaphore( int maxCount = 1 ); + ~Semaphore( void ); + + bool lock( int interval = 0 ); + bool unLock( void ); + int getCount( void ) const; + +private: + + int m_maxCount; + int m_count; + mutable Mutex m_mutex; + ConditionVariable m_condVar; +}; + +#endif // SEMAPHORE_HPP diff --git a/src/ConditionVariable.cpp b/src/ConditionVariable.cpp index d57d1d7..40865f9 100644 --- a/src/ConditionVariable.cpp +++ b/src/ConditionVariable.cpp @@ -24,21 +24,25 @@ int ConditionVariable::wait(const int interval) TRACE(this); if ( interval == 0 ) { return pthread_cond_wait( &m_condVar, - m_mutex.getPThreadMutex() ); + m_mutex.getPThreadMutex() ); } else { timespec tspec = intIntervalTotimespec(interval); + + TRACE("interval: " << interval << " tspec.tv_sec: " << tspec.tv_sec << " tspec.tv_nsec: " << tspec.tv_nsec ); return pthread_cond_timedwait( &m_condVar, m_mutex.getPThreadMutex(), &tspec); } } + int ConditionVariable::signal() { TRACE(this); return pthread_cond_signal( &m_condVar ); } + int ConditionVariable::broadcast() { TRACE(this); diff --git a/src/Semaphore.cpp b/src/Semaphore.cpp new file mode 100644 index 0000000..1ded631 --- /dev/null +++ b/src/Semaphore.cpp @@ -0,0 +1,54 @@ +#include "Semaphore.hpp" + +#include "ScopedLock.hpp" +#include "Common.hpp" + +Semaphore::Semaphore( int maxCount ) + : m_maxCount( maxCount ) + , m_count( maxCount ) + , m_mutex() + , m_condVar(m_mutex) +{ + TRACE(this); +} + + +Semaphore::~Semaphore( void ) +{ + TRACE(this); +} + + +bool Semaphore::lock( int interval ) +{ + TRACE(this); + ScopedLock sl(m_mutex); + if ( m_count == 0 ) { + if ( m_condVar.wait(interval) != 0 ) { + return false; + } + } + m_count -= 1; + return true; +} + + +bool Semaphore::unLock( void ) +{ + TRACE(this); + ScopedLock sc(m_mutex); + if ( m_count == m_maxCount ) { + return false; + } + m_count += 1; + m_condVar.signal(); + return true; +} + + +int Semaphore::getCount( void ) const +{ + TRACE(this); + ScopedLock sc(m_mutex); + return m_count; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 31994b7..e3dda00 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,6 +15,7 @@ test_ScopedLock.hpp test_ConditionalVariable.hpp test_Thread.hpp test_ThreadPool.hpp +test_Semaphore.hpp ) target_link_libraries(test CppUtils gcov) endif() diff --git a/test/run_test.sh b/test/run_test.sh index 4908719..94d106a 100755 --- a/test/run_test.sh +++ b/test/run_test.sh @@ -45,7 +45,7 @@ valgrind \ --malloc-fill=0xaa \ --free-fill=0xdd \ --suppressions=valgrind.supp \ - $test | tee $test.out; retval=$PIPESTATUS; (( $retval == 0 )); + $test | tee $test.out; retval=$PIPESTATUS # retval is 0 on success # or the number of failed cases diff --git a/test/test_Semaphore.hpp b/test/test_Semaphore.hpp new file mode 100644 index 0000000..befc116 --- /dev/null +++ b/test/test_Semaphore.hpp @@ -0,0 +1,105 @@ +#include + +#include "Semaphore.hpp" +#include "Thread.hpp" +#include "Common.hpp" + +class TestSemaphore : public CxxTest::TestSuite +{ +public: + + void testBasic( void ) + { + Semaphore s; + TS_ASSERT_EQUALS( s.getCount(), 1 ); + + TS_ASSERT_EQUALS( s.lock(), true ); + TS_ASSERT_EQUALS( s.getCount(), 0 ); + + TS_ASSERT_EQUALS( s.unLock(), true ); + TS_ASSERT_EQUALS( s.getCount(), 1 ); + + } + +private: + + class ThreadClassWithSemaphore : public Thread + { + public: + + ThreadClassWithSemaphore(Semaphore &semaphore) + : m_semaphore(semaphore) + { + TRACE(this); + } + ~ThreadClassWithSemaphore() { + TRACE(this); + } + + bool use( int timeout = 0 ) { + TRACE(this); + bool retval = m_semaphore.lock(timeout); + return retval; + } + + bool release( void ) { + TRACE(this); + return m_semaphore.unLock(); + } + + private: + + void* run( void ) { + TRACE(this); + while (m_isRunning) { + sleep(1); + } + return 0; + } + + Semaphore &m_semaphore; + + }; // class ThreadClassWithSemaphore + +public: + + void testWithTwoThreads( void ) + { + Semaphore semaphore(2); + TS_ASSERT_EQUALS( semaphore.getCount(), 2 ); + + ThreadClassWithSemaphore *t1 = new ThreadClassWithSemaphore(semaphore); + ThreadClassWithSemaphore *t2 = new ThreadClassWithSemaphore(semaphore); + t1->start(); + t2->start(); + + sleep(1); + + TS_ASSERT_EQUALS( t1->use(), true ); + TS_ASSERT_EQUALS( semaphore.getCount(), 1 ); + TS_ASSERT_EQUALS( t1->use(), true ); + TS_ASSERT_EQUALS( semaphore.getCount(), 0 ); + TS_ASSERT_EQUALS( t1->use(1), false ); + + TS_ASSERT_EQUALS( t2->use(1), false ); + TS_ASSERT_EQUALS( semaphore.getCount(), 0 ); + TS_ASSERT_EQUALS( t1->release(), true ); + TS_ASSERT_EQUALS( semaphore.getCount(), 1 ); + TS_ASSERT_EQUALS( t2->use(1), true ); + TS_ASSERT_EQUALS( semaphore.getCount(), 0 ); + + TS_ASSERT_EQUALS( t2->release(), true ); + TS_ASSERT_EQUALS( semaphore.getCount(), 1 ); + TS_ASSERT_EQUALS( t2->release(), true ); + TS_ASSERT_EQUALS( semaphore.getCount(), 2 ); + TS_ASSERT_EQUALS( t2->release(), false ); + + t1->stop(); + t2->stop(); + t1->join(); + t2->join(); + delete t1; + delete t2; + } + +}; diff --git a/test/test_Thread.hpp b/test/test_Thread.hpp index 9841ff6..85a9b2b 100644 --- a/test/test_Thread.hpp +++ b/test/test_Thread.hpp @@ -56,6 +56,7 @@ private: class ThreadClassWithSignal : public Thread { + public: ThreadClassWithSignal() { @@ -75,7 +76,7 @@ private: /** @note the function will get stopped before it finishes sleeping * If signal arrives after malloc, it will be a memory leak. */ - sleep(32); + sleep(665); void* retVal = malloc(sizeof(int)); *((int*)retVal) = 15; @@ -93,7 +94,9 @@ private: pthread_exit(retVal); } } - }; + + }; // class ThreadClassWithSignal + public: @@ -101,7 +104,7 @@ public: { ThreadClassWithSignal *m2 = new ThreadClassWithSignal; m2->start(); - sleep(3); + sleep(1); m2->sendSignal(SIGINT); void *retVal = m2->join();