Ticket #8797: 0001-thread-semaphore-implementation.patch
File 0001-thread-semaphore-implementation.patch, 23.6 KB (added by , 9 years ago) |
---|
-
new file oost/thread/apple/semaphore_dispatch.hpp
From b4252fa9ea36489f55b9c42a3bc14cc344bac9fc Mon Sep 17 00:00:00 2001 Message-Id: <b4252fa9ea36489f55b9c42a3bc14cc344bac9fc.1373273754.git.tim@klingt.org> From: Tim Blechmann <tim@klingt.org> Date: Mon, 8 Jul 2013 10:55:51 +0200 Subject: [PATCH] thread: semaphore implementation linux: posix semaphores osx/ios: dispatch semaphores win32: windows semaphores --- boost/thread/apple/semaphore_dispatch.hpp | 105 +++++++++++++++++ boost/thread/detail/semaphore_emulation.hpp | 91 +++++++++++++++ boost/thread/pthread/semaphore_posix.hpp | 170 ++++++++++++++++++++++++++++ boost/thread/semaphore.hpp | 69 +++++++++++ boost/thread/win32/semaphore_win32.hpp | 38 +++++++ libs/thread/doc/semaphore.qbk | 161 ++++++++++++++++++++++++++ libs/thread/doc/thread.qbk | 1 + libs/thread/src/win32/thread.cpp | 63 +++++++++++ libs/thread/test/Jamfile.v2 | 1 - libs/thread/test/test_semaphore.cpp | 124 ++++++++++++++++++++ 10 files changed, 822 insertions(+), 1 deletion(-) create mode 100644 boost/thread/apple/semaphore_dispatch.hpp create mode 100644 boost/thread/detail/semaphore_emulation.hpp create mode 100644 boost/thread/pthread/semaphore_posix.hpp create mode 100644 boost/thread/semaphore.hpp create mode 100644 boost/thread/win32/semaphore_win32.hpp create mode 100644 libs/thread/doc/semaphore.qbk create mode 100644 libs/thread/test/test_semaphore.cpp diff --git a/boost/thread/apple/semaphore_dispatch.hpp b/boost/thread/apple/semaphore_dispatch.hpp new file mode 100644 index 0000000..2bbce52
- + 1 // semaphore.hpp, osx/ios dispatch semaphores 2 // 3 // Copyright (C) 2013 Tim Blechmann 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 9 #ifndef BOOST_THREAD_APPLE_SEMAPHORE_DISPATCH_HPP 10 #define BOOST_THREAD_APPLE_SEMAPHORE_DISPATCH_HPP 11 12 #include <dispatch/dispatch.h> 13 14 #include <boost/thread/exceptions.hpp> 15 16 #ifdef BOOST_THREAD_USES_CHRONO 17 #include <boost/chrono/system_clocks.hpp> 18 #include <boost/chrono/ceil.hpp> 19 #endif 20 21 namespace boost { 22 23 class semaphore 24 { 25 BOOST_DELETED_FUNCTION(semaphore(semaphore const&)) 26 BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&)) 27 28 public: 29 semaphore(int i=0) 30 { 31 BOOST_ASSERT_MSG(i >= 0, "boost::semaphore constructor called with negative count"); 32 sem = dispatch_semaphore_create(i); 33 if (sem == NULL) 34 boost::throw_exception(thread_resource_error(system::errc::not_enough_memory, "boost::semaphore constructor failed in dispatch_semaphore_create")); 35 } 36 37 ~semaphore() 38 { 39 dispatch_release(sem); 40 } 41 42 void post() 43 { 44 dispatch_semaphore_signal(sem); 45 } 46 47 void wait() 48 { 49 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 50 } 51 52 bool try_wait(void) 53 { 54 const long status = dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW); 55 return status == 0; 56 } 57 58 #ifdef BOOST_THREAD_USES_CHRONO 59 template <class Rep, class Period> 60 bool try_wait_for(const chrono::duration<Rep, Period> & rel_time) 61 { 62 return try_wait_until(chrono::steady_clock::now() + rel_time); 63 } 64 65 template <class Clock, class Duration> 66 bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout ) 67 { 68 using namespace chrono; 69 system_clock::time_point s_now = system_clock::now(); 70 typename Clock::time_point c_now = Clock::now(); 71 return try_wait_until(s_now + ceil<nanoseconds>(timeout - c_now)); 72 } 73 74 template <class Duration> 75 bool try_wait_until(const chrono::time_point<chrono::system_clock, Duration>& t) 76 { 77 using namespace chrono; 78 typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; 79 return try_wait_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); 80 } 81 82 bool try_wait_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) 83 { 84 chrono::nanoseconds d = tp.time_since_epoch(); 85 timespec ts = boost::detail::to_timespec(d); 86 return do_wait_lock_until(dispatch_walltime(&ts, 0)); 87 } 88 89 private: 90 bool do_wait_lock_until(const dispatch_time_t timeout) 91 { 92 const long status = dispatch_semaphore_wait(sem, timeout); 93 return status == 0; 94 } 95 96 #endif // BOOST_THREAD_USES_CHRONO 97 98 99 private: 100 dispatch_semaphore_t sem; 101 }; 102 103 } 104 105 #endif // BOOST_THREAD_APPLE_SEMAPHORE_DISPATCH_HPP -
new file oost/thread/detail/semaphore_emulation.hpp
diff --git a/boost/thread/detail/semaphore_emulation.hpp b/boost/thread/detail/semaphore_emulation.hpp new file mode 100644 index 0000000..56ab97a
- + 1 // semaphore.hpp, mutex/condition_varibale emulation 2 // 3 // Copyright (C) 2013 Tim Blechmann 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 9 #ifndef BOOST_THREAD_DETAIL_SEMAPHORE_EMULATION_HPP 10 #define BOOST_THREAD_DETAIL_SEMAPHORE_EMULATION_HPP 11 12 #include <boost/bind.hpp> 13 #include <boost/noncopyable.hpp> 14 15 #include <boost/thread/mutex.hpp> 16 #include <boost/thread/condition_variable.hpp> 17 18 #ifdef BOOST_THREAD_USES_CHRONO 19 #include <boost/chrono/system_clocks.hpp> 20 #include <boost/chrono/ceil.hpp> 21 #endif 22 23 namespace boost { 24 25 class semaphore 26 { 27 BOOST_DELETED_FUNCTION(semaphore(semaphore const&)) 28 BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&)) 29 30 public: 31 semaphore(int i=0): 32 m_count(i) 33 { 34 BOOST_ASSERT_MSG(i >= 0, "boost::semaphore constructor called with negative count"); 35 } 36 37 void post(void) 38 { 39 mutex::scoped_lock lock(m_mutex); 40 ++m_count; 41 m_cond.notify_one(); 42 } 43 44 void wait(void) 45 { 46 mutex::scoped_lock lock(m_mutex); 47 m_cond.wait(lock, boost::bind(&semaphore::check_wakeup_condition, this)); 48 49 --m_count; 50 } 51 52 bool try_wait(void) 53 { 54 mutex::scoped_lock lock(m_mutex); 55 if (!check_wakeup_condition()) 56 return false; 57 58 --m_count; 59 return true; 60 } 61 62 #ifdef BOOST_THREAD_USES_CHRONO 63 template <class Rep, class Period> 64 bool try_wait_for(const chrono::duration<Rep, Period> & rel_time) 65 { 66 mutex::scoped_lock lock(m_mutex); 67 return m_cond.wait_for(lock, rel_time, boost::bind(&semaphore::check_wakeup_condition, this)); 68 } 69 70 template <class Clock, class Duration> 71 bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout ) 72 { 73 mutex::scoped_lock lock(m_mutex); 74 return m_cond.wait_until(lock, timeout, boost::bind(&semaphore::check_wakeup_condition, this)); 75 } 76 #endif // BOOST_THREAD_USES_CHRONO 77 78 private: 79 bool check_wakeup_condition() 80 { 81 return m_count > 0; 82 } 83 84 unsigned int m_count; 85 boost::mutex m_mutex; 86 boost::condition_variable m_cond; 87 }; 88 89 } 90 91 #endif // BOOST_THREAD_DETAIL_SEMAPHORE_EMULATION_HPP -
new file oost/thread/pthread/semaphore_posix.hpp
diff --git a/boost/thread/pthread/semaphore_posix.hpp b/boost/thread/pthread/semaphore_posix.hpp new file mode 100644 index 0000000..ca91297
- + 1 // semaphore.hpp, posix implementation 2 // 3 // Copyright (C) 2013 Tim Blechmann 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 9 10 #ifndef BOOST_THREAD_PTHREAD_SEMAPHORE_POSIX_HPP 11 #define BOOST_THREAD_PTHREAD_SEMAPHORE_POSIX_HPP 12 13 #include <semaphore.h> 14 15 #include <boost/assert.hpp> 16 #include <boost/thread/exceptions.hpp> 17 18 #ifdef BOOST_THREAD_USES_CHRONO 19 #include <boost/chrono/system_clocks.hpp> 20 #include <boost/chrono/ceil.hpp> 21 #endif 22 23 namespace boost { 24 25 class semaphore 26 { 27 BOOST_DELETED_FUNCTION(semaphore(semaphore const&)) 28 BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&)) 29 30 public: 31 semaphore(int i=0) 32 { 33 BOOST_ASSERT_MSG(i >= 0, "boost::semaphore constructor called with negative count"); 34 35 const int status = sem_init(&sem, 0, i); 36 if (status) 37 boost::throw_exception(thread_resource_error(status, "boost::semaphore constructor failed in sem_init")); 38 } 39 40 ~semaphore() 41 { 42 const int status = sem_destroy(&sem); 43 (void)status; 44 BOOST_ASSERT(!status); 45 } 46 47 void post() 48 { 49 const int status = sem_post(&sem); 50 51 switch (status) 52 { 53 case EOVERFLOW: 54 boost::throw_exception(thread_resource_error(status, "boost::semaphore post failed: Maximum allowable value would be exceeded")); 55 break; 56 57 case EINVAL: 58 BOOST_ASSERT(false); 59 60 default: 61 break; 62 } 63 } 64 65 void wait(void) 66 { 67 for (;;) 68 { 69 const int status = sem_wait(&sem); 70 if (status == 0) 71 return; 72 73 switch (errno) 74 { 75 case EINTR: // interrupted by a signal handler 76 continue; 77 78 case EINVAL: 79 default: 80 // we should not reach here 81 BOOST_ASSERT(false); 82 return; 83 } 84 } 85 } 86 87 bool try_wait(void) 88 { 89 const int status = sem_trywait(&sem); 90 if (status == 0) 91 return true; 92 93 switch (errno) 94 { 95 case EINVAL: 96 BOOST_ASSERT(false); 97 98 case EAGAIN: 99 return false; 100 101 default: 102 return false; 103 } 104 } 105 106 #ifdef BOOST_THREAD_USES_CHRONO 107 template <class Rep, class Period> 108 bool try_wait_for(const chrono::duration<Rep, Period> & rel_time) 109 { 110 return try_wait_until(chrono::steady_clock::now() + rel_time); 111 } 112 113 template <class Clock, class Duration> 114 bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout ) 115 { 116 using namespace chrono; 117 system_clock::time_point s_now = system_clock::now(); 118 typename Clock::time_point c_now = Clock::now(); 119 return try_wait_until(s_now + ceil<nanoseconds>(timeout - c_now)); 120 } 121 122 template <class Duration> 123 bool try_wait_until(const chrono::time_point<chrono::system_clock, Duration>& t) 124 { 125 using namespace chrono; 126 typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; 127 return try_wait_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); 128 } 129 130 bool try_wait_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) 131 { 132 chrono::nanoseconds d = tp.time_since_epoch(); 133 timespec ts = boost::detail::to_timespec(d); 134 return do_wait_lock_until(ts); 135 } 136 137 private: 138 bool do_wait_lock_until(struct timespec const & timeout) 139 { 140 for (;;) { 141 const int status = sem_timedwait(&sem, &timeout); 142 if (status == 0) 143 return true; 144 145 switch (errno) 146 { 147 case ETIMEDOUT: 148 return false; 149 150 case EINTR: // interrupted by a signal handler 151 continue; 152 153 case EINVAL: 154 case EAGAIN: 155 default: 156 BOOST_ASSERT(false); 157 return false; 158 } 159 } 160 } 161 162 #endif // BOOST_THREAD_USES_CHRONO 163 164 private: 165 sem_t sem; 166 }; 167 168 } 169 170 #endif /* BOOST_THREAD_PTHREAD_SEMAPHORE_POSIX_HPP */ -
new file oost/thread/semaphore.hpp
diff --git a/boost/thread/semaphore.hpp b/boost/thread/semaphore.hpp new file mode 100644 index 0000000..0953df2
- + 1 // semaphore.hpp 2 // 3 // Copyright (C) 2013 Tim Blechmann 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 9 #ifndef BOOST_THREAD_SEMAPHORE_HPP 10 #define BOOST_THREAD_SEMAPHORE_HPP 11 12 #include <boost/thread/detail/config.hpp> 13 14 15 // configuration helpers 16 17 #ifdef BOOST_HAS_UNISTD_H 18 #include <unistd.h> 19 20 #if (_POSIX_SEMAPHORES - 0) >= 200112L 21 #define BOOST_THREAD_POSIX_SEMAPHORES 22 #endif 23 24 #endif // BOOST_HAS_UNISTD_H 25 26 #if defined(__APPLE__) 27 #include <Availability.h> 28 29 // OSX 30 #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED 31 32 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_6 33 #define BOOST_THREAD_DISPATCH_SEMAPHORES 34 #endif 35 36 #endif 37 38 // iOS 39 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED 40 41 // untested! 42 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0 43 #define BOOST_THREAD_DISPATCH_SEMAPHORES 44 #endif 45 46 #endif 47 48 49 #endif // __APPLE__ 50 51 52 // implementation 53 54 #if defined(BOOST_THREAD_PLATFORM_WIN32) 55 #include <boost/thread/win32/semaphore_win32.hpp> 56 57 #elif defined(BOOST_THREAD_POSIX_SEMAPHORES) 58 #include <boost/thread/pthread/semaphore_posix.hpp> 59 60 #elif defined(BOOST_THREAD_DISPATCH_SEMAPHORES) 61 #include <boost/thread/apple/semaphore_dispatch.hpp> 62 63 #else 64 #include <boost/thread/detail/semaphore_emulation.hpp> 65 66 #endif 67 68 69 #endif // BOOST_THREAD_SEMAPHORE_HPP -
new file oost/thread/win32/semaphore_win32.hpp
diff --git a/boost/thread/win32/semaphore_win32.hpp b/boost/thread/win32/semaphore_win32.hpp new file mode 100644 index 0000000..a6d8cf7
- + 1 // semaphore.hpp, win32 semaphores 2 // 3 // Copyright (C) 2013 Tim Blechmann 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 9 #ifndef BOOST_THREAD_WIN32_SEMAPHORE_WIN32_HPP 10 #define BOOST_THREAD_WIN32_SEMAPHORE_WIN32_HPP 11 12 #include <boost/thread/win32/thread_primitives.hpp> 13 14 namespace boost { 15 16 class semaphore 17 { 18 BOOST_DELETED_FUNCTION(semaphore(semaphore const&)) 19 BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&)) 20 21 public: 22 semaphore(int i=0); 23 24 ~semaphore(); 25 26 void post(); 27 28 bool wait(); 29 30 bool try_wait(void); 31 32 private: 33 detail::win32::HANDLE sem_; 34 }; 35 36 } 37 38 #endif // BOOST_THREAD_WIN32_SEMAPHORE_WIN32_HPP -
new file libs/thread/doc/semaphore.qbk
diff --git a/libs/thread/doc/semaphore.qbk b/libs/thread/doc/semaphore.qbk new file mode 100644 index 0000000..b1f90f8
- + 1 [/ 2 (C) Copyright 2007-8 Anthony Williams. 3 (C) Copyright 2013 Tim Blechmann. 4 (C) Copyright 2005-2012 Ion Gaztanaga 5 Distributed under the Boost Software License, Version 1.0. 6 (See accompanying file LICENSE_1_0.txt or copy at 7 http://www.boost.org/LICENSE_1_0.txt). 8 ] 9 10 [section:semaphore semaphores] 11 12 [section:semaphores_whats_a_semaphores What's A Semaphore?] 13 14 A semaphore is a synchronization mechanism between processes based in an internal 15 count that offers two basic operations: 16 17 * [*Wait]: Tests the value of the semaphore count, and waits if the value is less than or 18 equal than 0. Otherwise, decrements the semaphore count. 19 20 * [*Post]: Increments the semaphore count. If any process is blocked, one of those processes 21 is awoken. 22 23 If the initial semaphore count is initialized to 1, a [*Wait] operation is equivalent to a 24 mutex locking and [*Post] is equivalent to a mutex unlocking. This type of semaphore is known 25 as a [*binary semaphore]. 26 27 Although semaphores can be used like mutexes, they have a unique feature: unlike mutexes, 28 a [*Post] operation need not be executed by the same thread/process that executed the 29 [*Wait] operation. 30 31 [endsect] 32 33 [section:semaphore_class Class `semaphore`] 34 35 #include <boost/thread/semaphore.hpp> 36 37 namespace boost 38 { 39 class semaphore 40 { 41 public: 42 semaphore(int initial_count = 0); 43 44 semaphore(semaphore const&) = delete; 45 semaphore& operator=(semaphore const&) = delete; 46 47 void post(); 48 void wait(); 49 bool try_wait(); 50 51 #ifdef BOOST_THREAD_USES_CHRONO 52 template <class Rep, class Period> 53 bool try_wait_for(const chrono::duration<Rep, Period> & duration); 54 55 template <class Clock, class Duration> 56 bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout); 57 #endif 58 }; 59 } 60 61 62 [section:constructor `semaphore()`] 63 64 [variablelist 65 66 [[Effects:] [Constructs an object of class `semaphore`. The semaphore is initialized to `initial_count`, 67 which is expected to be non-negative.]] 68 69 [[Throws:] [__thread_resource_error__ if an error occurs.]] 70 71 ] 72 73 [endsect] 74 75 76 [section:destructor `~semaphore()`] 77 78 [variablelist 79 80 [[Precondition:] [No thread is waiting on `*this`]] 81 82 [[Effects:] [Destroys the object.]] 83 84 [[Throws:] [Nothing.]] 85 86 ] 87 88 [endsect] 89 90 91 [section:post `post()`] 92 93 [variablelist 94 95 [[Effects:] [Increments the semaphore count. If a thread is waiting for `*this`, it will be unblocked.]] 96 97 [[Throws:] [__thread_resource_error__ if an error (e.g. counter overflow) occurs.]] 98 99 ] 100 101 [endsect] 102 103 104 [section:wait `wait()`] 105 106 [variablelist 107 108 [[Effects:] [If the semaphore count is positive, it atomically decrements it and returns. Otherwise blocks 109 the current thread, until it can successfully decrement a positive semaphore count.]] 110 111 [[Throws:] [__thread_resource_error__ if an error occurs.]] 112 113 ] 114 115 [endsect] 116 117 118 [section:try_wait `try_wait()`] 119 120 [variablelist 121 122 [[Effects:] [If the semaphore count is positive, it atomically decrements it and returns `true`. Otherwise `false`.]] 123 124 [[Throws:] [__thread_resource_error__ if an error occurs.]] 125 126 ] 127 128 [endsect] 129 130 131 [section:try_wait `template <class Rep, class Period> bool try_wait_for(const chrono::duration<Rep, Period> & duration)`] 132 133 [variablelist 134 135 [[Effects:] [If the semaphore count is positive, it atomically decrements it and returns `true`. Otherwise it waits for the semaphore 136 for `duration`.]] 137 138 [[Throws:] [__thread_resource_error__ if an error occurs.]] 139 140 ] 141 142 [endsect] 143 144 145 [section:try_wait `template <class Clock, class Duration> bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout)`] 146 147 [variablelist 148 149 [[Effects:] [If the semaphore count is positive, it atomically decrements it and returns `true`. Otherwise it waits for the semaphore 150 until `timeout`.]] 151 152 [[Throws:] [__thread_resource_error__ if an error occurs.]] 153 154 ] 155 156 157 [endsect] 158 159 [endsect] 160 161 [endsect] -
libs/thread/doc/thread.qbk
diff --git a/libs/thread/doc/thread.qbk b/libs/thread/doc/thread.qbk index 7acc256..32231af 100644
a b 241 241 [include barrier.qbk] 242 242 [/include latch.qbk] 243 243 [include futures.qbk] 244 [include semaphore.qbk] 244 245 [/include async_executors.qbk] 245 246 [endsect] 246 247 -
libs/thread/src/win32/thread.cpp
diff --git a/libs/thread/src/win32/thread.cpp b/libs/thread/src/win32/thread.cpp index 28dd8d4..4b1e61e 100644
a b 20 20 #include <boost/thread/condition_variable.hpp> 21 21 #include <boost/thread/detail/tss_hooks.hpp> 22 22 #include <boost/thread/future.hpp> 23 #include <boost/thread/semaphore.hpp> 23 24 24 25 #include <boost/assert.hpp> 25 26 #if defined BOOST_THREAD_USES_DATETIME … … namespace boost 747 748 current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); 748 749 } 749 750 } 751 752 semaphore::semaphore(int i) 753 { 754 BOOST_ASSERT_MSG(i >= 0, "boost::semaphore constructor called with negative count"); 755 756 sem_ = CreateSemaphore(NULL, i, (std::numeric_limits<LONG>::max)(), NULL); 757 if (!sem_) 758 boost::throw_exception(thread_resource_error(GetLastError(), "boost::semaphore constructor failed in CreateSemaphore")); 759 } 760 761 semaphore::~semaphore() 762 { 763 CloseHandle(sem_); 764 } 765 766 void semaphore::post() 767 { 768 const BOOL status = ReleaseSemaphore(sem_, 1, NULL); 769 if (status == 0) 770 boost::throw_exception(thread_resource_error(GetLastError(), "boost::semaphore::post failed in ReleaseSemaphore")); 771 } 772 773 bool semaphore::wait() 774 { 775 const DWORD status = WaitForSingleObject(sem_, INFINITE); 776 777 switch (status) 778 { 779 case WAIT_OBJECT_0: 780 return true; 781 782 case WAIT_FAILED: 783 boost::throw_exception(thread_resource_error(GetLastError(), "boost::semaphore::wait failed in ReleaseSemaphore")); 784 785 default: 786 BOOST_ASSERT(false); 787 return false; 788 } 789 } 790 791 bool semaphore::try_wait() 792 { 793 const DWORD status = WaitForSingleObject(sem_, 0L); 794 795 switch (status) 796 { 797 case WAIT_OBJECT_0: 798 return true; 799 800 case WAIT_TIMEOUT: 801 return false; 802 803 case WAIT_FAILED: 804 boost::throw_exception(thread_resource_error(GetLastError(), "boost::semaphore::wait failed in ReleaseSemaphore")); 805 806 default: 807 BOOST_ASSERT(false); 808 return false; 809 } 810 return true; 811 } 812 750 813 } 751 814 -
libs/thread/test/Jamfile.v2
diff --git a/libs/thread/test/Jamfile.v2 b/libs/thread/test/Jamfile.v2 index 2081b95..13d275f 100644
a b rule thread-compile ( sources : reqs * : name ) 639 639 test-suite ts_sync_bounded_queue 640 640 : 641 641 [ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/single_thread_pass.cpp : sync_bounded_queue__single_thread_p ] 642 [ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_queue__multi_thread_p ]643 642 ; 644 643 645 644 #explicit ts_this_thread ; -
new file libs/thread/test/test_semaphore.cpp
diff --git a/libs/thread/test/test_semaphore.cpp b/libs/thread/test/test_semaphore.cpp new file mode 100644 index 0000000..fcea549
- + 1 // Copyright (C) 2013 Tim Blechmann 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #include <boost/test/unit_test.hpp> 7 8 #include <boost/thread.hpp> 9 #include <boost/thread/semaphore.hpp> 10 11 #include <boost/typeof/typeof.hpp> 12 13 static void test_semaphore_post_wait() 14 { 15 boost::semaphore sem(0); 16 17 sem.post(); 18 sem.wait(); 19 } 20 21 22 static void test_semaphore_try_wait() 23 { 24 boost::semaphore sem(0); 25 26 BOOST_REQUIRE(!sem.try_wait()); 27 sem.post(); 28 BOOST_REQUIRE(sem.try_wait()); 29 } 30 31 32 struct semaphore_wait_and_post_test 33 { 34 void run() 35 { 36 boost::thread post_thread(boost::bind(&semaphore_wait_and_post_test::wait_and_post, this)); 37 sem_.wait(); 38 } 39 40 void wait_and_post() 41 { 42 boost::this_thread::sleep_for(boost::chrono::seconds(1)); 43 sem_.post(); 44 } 45 46 static void run_test() 47 { 48 semaphore_wait_and_post_test test; 49 test.run(); 50 } 51 52 boost::semaphore sem_; 53 boost::thread thread_; 54 }; 55 56 static void test_semaphore_wait_for() 57 { 58 using namespace boost; 59 60 semaphore sem(0); 61 62 BOOST_AUTO(start, chrono::system_clock::now()); 63 64 BOOST_REQUIRE(!sem.try_wait_for(chrono::milliseconds(500))); 65 66 BOOST_AUTO(end, chrono::system_clock::now()); 67 BOOST_AUTO(wait_time, end - start); 68 69 // guessing! 70 BOOST_REQUIRE( wait_time > chrono::milliseconds(450) ); 71 BOOST_REQUIRE( wait_time < chrono::milliseconds(1000) ); 72 73 sem.post(); 74 75 BOOST_REQUIRE(sem.try_wait_for(chrono::milliseconds(500))); 76 } 77 78 static void test_semaphore_wait_until() 79 { 80 using namespace boost; 81 82 semaphore sem(0); 83 { 84 BOOST_AUTO(now, chrono::system_clock::now()); 85 BOOST_AUTO(timeout, now + chrono::milliseconds(500)); 86 87 BOOST_REQUIRE(!sem.try_wait_until(timeout)); 88 89 BOOST_AUTO(end, chrono::system_clock::now()); 90 BOOST_AUTO(timeout_delta, end - timeout); 91 92 // guessing! 93 BOOST_REQUIRE( timeout_delta > chrono::milliseconds(-400) ); 94 BOOST_REQUIRE( timeout_delta < chrono::milliseconds(400) ); 95 } 96 97 sem.post(); 98 99 { 100 BOOST_AUTO(start, chrono::system_clock::now()); 101 BOOST_AUTO(timeout, start + chrono::milliseconds(500)); 102 103 BOOST_REQUIRE(sem.try_wait_until(timeout)); 104 105 BOOST_AUTO(end, chrono::system_clock::now()); 106 107 // guessing! 108 BOOST_REQUIRE( (end - start) < chrono::milliseconds(100) ); 109 } 110 } 111 112 113 boost::unit_test::test_suite* init_unit_test_suite(int, char*[]) 114 { 115 boost::unit_test::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: semaphore test suite"); 116 117 test->add(BOOST_TEST_CASE(test_semaphore_post_wait)); 118 test->add(BOOST_TEST_CASE(test_semaphore_try_wait)); 119 test->add(BOOST_TEST_CASE(semaphore_wait_and_post_test::run_test)); 120 121 test->add(BOOST_TEST_CASE(test_semaphore_wait_for)); 122 test->add(BOOST_TEST_CASE(test_semaphore_wait_until)); 123 return test; 124 }