Provide a semaphore class optimizing post
.
More...
Namespaces |
namespace | bslmt |
Detailed Description
- Outline
-
-
- Purpose:
- Provide a semaphore class optimizing
post
.
-
- Classes:
-
- See also:
- Component bslmt_semaphore
-
- Description:
- This component defines a semaphore,
bslmt::FastPostSemaphore
, with the post
operation being optimized at the potential expense of other operations. In particular, bslmt::FastPostSemaphore
is an efficient synchronization primitive that enables sharing of a counted number of resources. bslmt::FastPostSemaphore
supports the methods timedWait
, enable
, and disable
in addition to the standard semaphore methods.
- Commonly, during periods of time when the protected resource is scarce (the semaphore count is frequently zero) and threads are frequently blocked on wait methods, pessimizing the performance of the threads that block will have little effect on overall performance. In this case, optimizing
post
may be a performance improvement. Note that when the resource is plentiful, there are no blocked threads and we expect the differences between semaphore implementations to be trivial.
-
- 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)
.
-
- Usage:
- This section illustrates intended use of this component.
-
- Example 1: A Simple Queue:
- This example illustrates a very simple fixed-size queue where potential clients can push integers to a queue, and later retrieve the integer values from the queue in FIFO order. Also,
waitUntilEmpty
is implemented to depict the common usage of getDisabledState
.
- First, we define the
IntQueue
class: Next, implement the queue:
IntQueue::IntQueue(bsl::size_t capacity, bslma::Allocator *basicAllocator)
: d_data(capacity, basicAllocator)
, d_pushSem(static_cast<int>(capacity))
, d_popSem(0)
, d_pushIdx(0)
, d_popIdx(0)
, d_emptyMutex()
, d_emptyCondition()
{
}
void IntQueue::disablePopFront()
{
d_popSem.disable();
}
void IntQueue::enablePopFront()
{
d_popSem.enable();
}
int IntQueue::popFront(int *value)
{
int rv = d_popSem.wait();
if (0 != rv) {
return rv;
}
*value = d_data[d_popIdx++ % d_data.size()];
d_pushSem.post();
if (0 == d_popSem.getValue()) {
{
bslmt::LockGuard<bslmt::Mutex> guard(&d_emptyMutex);
}
d_emptyCondition.broadcast();
}
return 0;
}
int IntQueue::pushBack(int value)
{
int rv = d_pushSem.wait();
if (0 != rv) {
return rv;
}
d_data[d_pushIdx++ % d_data.size()] = value;
d_popSem.post();
return 0;
}
int IntQueue::waitUntilEmpty() const
{
bslmt::LockGuard<bslmt::Mutex> guard(&d_emptyMutex);
int state = d_popSem.getDisabledState();
while (d_popSem.getValue()) {
if (state != d_popSem.getDisabledState()) {
return e_DISABLED;
}
d_emptyCondition.wait(&d_emptyMutex);
}
return e_SUCCESS;
}
Then, declare an instance of IntQueue
: Next, populate some values: assert(0 == queue.pushBack(5));
assert(0 == queue.pushBack(7));
assert(0 == queue.pushBack(3));
Now, pop and verify the values: int value;
assert(0 == queue.popFront(&value));
assert(5 == value);
assert(0 == queue.popFront(&value));
assert(7 == value);
assert(0 == queue.popFront(&value));
assert(3 == value);
Finally, use waitUntilEmpty
to verify the queue is empty: assert(IntQueue::e_SUCCESS == queue.waitUntilEmpty());