Ticket #8797: 0001-thread-semaphore-implementation.patch

File 0001-thread-semaphore-implementation.patch, 23.6 KB (added by timblechmann, 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
     21namespace boost {
     22
     23class semaphore
     24{
     25  BOOST_DELETED_FUNCTION(semaphore(semaphore const&))
     26  BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&))
     27
     28public:
     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
     89private:
     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
     99private:
     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
     23namespace boost {
     24
     25class semaphore
     26{
     27        BOOST_DELETED_FUNCTION(semaphore(semaphore const&))
     28    BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&))
     29
     30public:
     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
     78private:
     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
     23namespace boost {
     24
     25class semaphore
     26{
     27  BOOST_DELETED_FUNCTION(semaphore(semaphore const&))
     28  BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&))
     29
     30public:
     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
     137private:
     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
     164private:
     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
     14namespace boost {
     15
     16class semaphore
     17{
     18  BOOST_DELETED_FUNCTION(semaphore(semaphore const&))
     19  BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&))
     20
     21public:
     22  semaphore(int i=0);
     23
     24  ~semaphore();
     25
     26  void post();
     27
     28  bool wait();
     29
     30  bool try_wait(void);
     31
     32private:
     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
     14A semaphore is a synchronization mechanism between processes based in an internal
     15count 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
     23If the initial semaphore count is initialized to 1, a [*Wait] operation is equivalent to a
     24mutex locking and [*Post] is equivalent to a mutex unlocking. This type of semaphore is known
     25as a [*binary semaphore].
     26
     27Although semaphores can be used like mutexes, they have a unique feature: unlike mutexes,
     28a [*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`,
     67which 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
     109the 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
     136for `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
     150until `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  
    241241[include barrier.qbk]
    242242[/include latch.qbk]
    243243[include futures.qbk]
     244[include semaphore.qbk]
    244245[/include async_executors.qbk]
    245246[endsect]
    246247
  • 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  
    2020#include <boost/thread/condition_variable.hpp>
    2121#include <boost/thread/detail/tss_hooks.hpp>
    2222#include <boost/thread/future.hpp>
     23#include <boost/thread/semaphore.hpp>
    2324
    2425#include <boost/assert.hpp>
    2526#if defined BOOST_THREAD_USES_DATETIME
    namespace boost  
    747748        current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
    748749      }
    749750    }
     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
    750813}
    751814
  • 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 )  
    639639    test-suite ts_sync_bounded_queue
    640640    :
    641641          [ 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 ]
    643642    ;
    644643
    645644    #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
     13static void test_semaphore_post_wait()
     14{
     15  boost::semaphore sem(0);
     16
     17  sem.post();
     18  sem.wait();
     19}
     20
     21
     22static 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
     32struct 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
     56static 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
     78static 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
     113boost::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}