diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-11-17 22:21:09 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-11-17 22:21:09 +0000 |
commit | 22fe281b639187960a9ca92c58676ad55bcc0769 (patch) | |
tree | 06f9a096cd1421e0b301e1ca89dd88dfd76aaad6 | |
parent | Improve core with traits and decltype for working with functions that return ... (diff) | |
download | libadhocutil-22fe281b639187960a9ca92c58676ad55bcc0769.tar.bz2 libadhocutil-22fe281b639187960a9ca92c58676ad55bcc0769.tar.xz libadhocutil-22fe281b639187960a9ca92c58676ad55bcc0769.zip |
Add a portable semaphore class with timeout support
-rw-r--r-- | libadhocutil/Jamfile.jam | 5 | ||||
-rw-r--r-- | libadhocutil/semaphore.cpp | 40 | ||||
-rw-r--r-- | libadhocutil/semaphore.h | 29 | ||||
-rw-r--r-- | libadhocutil/unittests/Jamfile.jam | 11 | ||||
-rw-r--r-- | libadhocutil/unittests/testSemaphore.cpp | 44 |
5 files changed, 128 insertions, 1 deletions
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 : : <name>boost_unit_test_framework ; +lib boost_system ; +lib boost_thread ; lib Ice : ; lib IceUtil ; lib pthread ; @@ -15,6 +16,8 @@ lib adhocutil : : <include>. <library>iceall + <library>boost_system + <library>boost_thread <library>curl <library>dl <cflags>-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 <boost/thread/condition.hpp> +#include <boost/thread/mutex.hpp> +#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 @@ -165,6 +165,17 @@ run ; run + testSemaphore.cpp + : : : + <define>BOOST_TEST_DYN_LINK + <library>..//adhocutil + <library>boost_utf + <library>boost_system + : + testSemaphore + ; + +run testException.cpp : : : <define>BOOST_TEST_DYN_LINK 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 <boost/test/unit_test.hpp> + +#include <thread> +#include <semaphore.h> + +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(); +} + |