From 22fe281b639187960a9ca92c58676ad55bcc0769 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 17 Nov 2015 22:21:09 +0000 Subject: Add a portable semaphore class with timeout support --- libadhocutil/Jamfile.jam | 5 +++- libadhocutil/semaphore.cpp | 40 +++++++++++++++++++++++++++++ libadhocutil/semaphore.h | 29 +++++++++++++++++++++ libadhocutil/unittests/Jamfile.jam | 11 ++++++++ libadhocutil/unittests/testSemaphore.cpp | 44 ++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 libadhocutil/semaphore.cpp create mode 100644 libadhocutil/semaphore.h create mode 100644 libadhocutil/unittests/testSemaphore.cpp diff --git a/libadhocutil/Jamfile.jam b/libadhocutil/Jamfile.jam index 861509a..c82dade 100644 --- a/libadhocutil/Jamfile.jam +++ b/libadhocutil/Jamfile.jam @@ -1,7 +1,8 @@ import package ; import lex ; -lib boost_utf : : boost_unit_test_framework ; +lib boost_system ; +lib boost_thread ; lib Ice : ; lib IceUtil ; lib pthread ; @@ -15,6 +16,8 @@ lib adhocutil : : . iceall + boost_system + boost_thread curl dl -fvisibility=hidden diff --git a/libadhocutil/semaphore.cpp b/libadhocutil/semaphore.cpp new file mode 100644 index 0000000..0500445 --- /dev/null +++ b/libadhocutil/semaphore.cpp @@ -0,0 +1,40 @@ +#include "semaphore.h" + +namespace AdHoc { + Semaphore::Semaphore(unsigned int initial) : count(initial) + { + } + + void + Semaphore::notify() + { + boost::mutex::scoped_lock lock(mutex); + ++count; + condition.notify_one(); + } + + void + Semaphore::wait() + { + boost::mutex::scoped_lock lock(mutex); + while (!count) { + condition.wait(lock); + } + --count; + } + + bool + Semaphore::wait(unsigned int timeout) + { + const boost::system_time expiry = boost::get_system_time() + boost::posix_time::milliseconds(timeout); + boost::mutex::scoped_lock lock(mutex); + while (!count) { + if (!condition.timed_wait(lock, expiry)) { + return false; + } + } + --count; + return true; + } +} + diff --git a/libadhocutil/semaphore.h b/libadhocutil/semaphore.h new file mode 100644 index 0000000..de10333 --- /dev/null +++ b/libadhocutil/semaphore.h @@ -0,0 +1,29 @@ +#ifndef ADHOCUTIL_SEMAPHORE_H +#define ADHOCUTIL_SEMAPHORE_H + +// Borrowed from StackOverflow +// http://stackoverflow.com/questions/4792449/c0x-has-no-semaphores-how-to-synchronize-threads + +#include +#include +#include "visibility.h" + +namespace AdHoc { + /// A portable semaphore with timeout support + class DLL_PUBLIC Semaphore { + public: + Semaphore(unsigned int initial = 0); + + void notify(); + void wait(); + bool wait(unsigned int); + + private: + boost::mutex mutex; + boost::condition_variable condition; + unsigned long count; + }; +} + +#endif + diff --git a/libadhocutil/unittests/Jamfile.jam b/libadhocutil/unittests/Jamfile.jam index 0961f31..334b47e 100644 --- a/libadhocutil/unittests/Jamfile.jam +++ b/libadhocutil/unittests/Jamfile.jam @@ -164,6 +164,17 @@ run testFactory ; +run + testSemaphore.cpp + : : : + BOOST_TEST_DYN_LINK + ..//adhocutil + boost_utf + boost_system + : + testSemaphore + ; + run testException.cpp : : : diff --git a/libadhocutil/unittests/testSemaphore.cpp b/libadhocutil/unittests/testSemaphore.cpp new file mode 100644 index 0000000..b5e435e --- /dev/null +++ b/libadhocutil/unittests/testSemaphore.cpp @@ -0,0 +1,44 @@ +#define BOOST_TEST_MODULE Semaphore +#include + +#include +#include + +BOOST_AUTO_TEST_CASE( addRemoveOne ) +{ + AdHoc::Semaphore s; + s.notify(); + s.wait(); +} + +BOOST_AUTO_TEST_CASE( addRemoveSome ) +{ + AdHoc::Semaphore s; + s.notify(); + s.notify(); + s.notify(); + s.wait(); + s.wait(); + s.wait(); +} + +BOOST_AUTO_TEST_CASE( addRemoveTimeOut ) +{ + AdHoc::Semaphore s; + s.notify(); + s.wait(); + BOOST_REQUIRE_EQUAL(false, s.wait(100)); + BOOST_REQUIRE_EQUAL(false, s.wait(0)); +} + +BOOST_AUTO_TEST_CASE( addRemoveWait ) +{ + AdHoc::Semaphore s; + s.notify(); + s.wait(); + std::thread th([&s]() { usleep(100000); s.notify(); }); + BOOST_REQUIRE_EQUAL(false, s.wait(1)); + s.wait(); + th.join(); +} + -- cgit v1.2.3