Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmt_timedsemaphore
[Package bslmt]

Provide a timed semaphore class. More...

Namespaces

namespace  bslmt

Detailed Description

Outline
Purpose:
Provide a timed semaphore class.
Classes:
bslmt::TimedSemaphore timed semaphore class
See also:
Component bslmt_semaphore
Description:
This component defines a portable and efficient thread synchronization primitive. In particular, bslmt::TimedSemaphore is an efficient synchronization primitive that enables sharing of a counted number of resources or exclusive access.
bslmt::TimedSemaphore differs from bslmt::Semaphore in that the former supports a timedWait method, whereas the latter does not. In addition, bslmt::Semaphore has a getValue accessor, whereas bslmt::TimedSemaphore does not. In the case of the timed semaphore, getValue cannot be implemented efficiently on all platforms, so that method is intentionally not provided.
Supported Clock-Types:
bsls::SystemClockType supplies the enumeration indicating the system clock on which timeouts supplied to other methods should be based. If the clock type indicated at construction is bsls::SystemClockType::e_REALTIME, the absTime argument passed to the timedWait method should be expressed as an absolute offset since 00:00:00 UTC, January 1, 1970 (which matches the epoch used in bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME). If the clock type indicated at construction is bsls::SystemClockType::e_MONOTONIC, the absTime argument passed to the timedWait method should be expressed as an absolute offset since the epoch of this clock (which matches the epoch used in bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC).
On platforms that support bsl::chrono, there are constructors that take bsl::chrono-style clocks. If the clock type indicated at construction is bsl::chrono::system_clock, then the results will be the same as if bsls::SystemClockType::e_REALTIME was indicated. If the clock type indicated at construction is bsl::chrono::steady_clock, then the results will be the same as if bsls::SystemClockType::e_MONOTONIC was indicated. Constructing from a user-defined clock is not supported.
Usage:
This example illustrates a very simple queue where potential clients can push integers to a queue, and later retrieve the integer values from the queue in FIFO order. It illustrates two potential uses of semaphores: to enforce exclusive access, and to allow resource sharing. This queue allows clients to set a limit on how long they wait to retrieve values.
  class IntQueue {
      // FIFO queue of integer values.

      // DATA
      bsl::deque<int>       d_queue;       // underlying queue
      bslmt::TimedSemaphore d_resourceSem; // resource-availability semaphore
      bslmt::TimedSemaphore d_mutexSem;    // mutual-access semaphore

      // NOT IMPLEMENTED
      IntQueue(const IntQueue&);
      IntQueue& operator=(const IntQueue&);

    public:
      // CREATORS
      explicit IntQueue(bslma::Allocator *basicAllocator = 0);
          // Create an 'IntQueue' object.  Optionally specified a
          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
          // 0, the currently installed default allocator is used.

      ~IntQueue();
          // Destroy this 'IntQueue' object.

      // MANIPULATORS
      int getInt(int *result, int maxWaitSeconds = 0);
          // Load the first integer in this queue into the specified 'result'
          // and return 0 unless the operation takes more than the optionally
          // specified 'maxWaitSeconds', in which case return a nonzero value
          // and leave 'result' unmodified.

      void pushInt(int value);
          // Push the specified 'value' to this 'IntQueue' object.
  };
Note that the IntQueue constructor increments the count of the semaphore to 1 so that values can be pushed into the queue immediately following construction:
  // CREATORS
  IntQueue::IntQueue(bslma::Allocator *basicAllocator)
  : d_queue(basicAllocator)
  , d_resourceSem(bsls::SystemClockType::e_MONOTONIC)
  {
      d_mutexSem.post();
  }

  IntQueue::~IntQueue()
  {
      d_mutexSem.wait();  // Wait for potential modifier.
  }

  // MANIPULATORS
  int IntQueue::getInt(int *result, int maxWaitSeconds)
  {
      // Waiting for resources.
      if (0 == maxWaitSeconds) {
          d_resourceSem.wait();
      } else {
          bsls::TimeInterval absTime = bsls::SystemTime::nowMonotonicClock()
              .addSeconds(maxWaitSeconds);
          int rc = d_resourceSem.timedWait(absTime);
          if (0 != rc) {
             return rc;
          }
      }

      // 'd_mutexSem' is used for exclusive access.
      d_mutexSem.wait();       // lock
      *result = d_queue.back();
      d_queue.pop_back();
      d_mutexSem.post();       // unlock

      return 0;
  }

  void IntQueue::pushInt(int value)
  {
      d_mutexSem.wait();
      d_queue.pushFront(value);
      d_mutexSem.post();

      d_resourceSem.post();  // Signal that we have resources available.
  }