466 30.ACross‐PlatformMultithreadingFramework
The pseudocode in Listing 30.3 is one of three separate cases that require
distinct handling, depending on the timeout value passed to the
Wait() method.
It shows the execution path when passing an infinite timeout value. If we use a
timeout value of zero, then we just test the current signal state and return imme-
diately. In this case, we only execute the first block and skip the loop. If neither
zero nor infinite is used as the timeout value, then we can use the same code as in
the listing with two minor changes. First, we use
pthread_cond_timedwait() to
wait on the condition variable with a given timeout. The second adaption is that
our
Wait() method has to return false in case pthread_cond_timedwait() re-
turns
ETIMEDOUT.
The last method, which is rather easy to implement, is used to set an event’s
state to nonsignaled and is called
Reset(). All we need to do is to obtain the lock
on our mutex and set the event’s signal state to false.
Thanks to the flexibility of System V semaphores, we can easily rebuild the
functionality of an event using a binary semaphore. Construction and cleanup is
performed exactly as described for the
BasicSemaphore class. The value of our
semaphore is directly mapped to the event state—a value of one indicates non-
signaled and a value of zero represents a signaled state. The
Set() method is a
simple call to
semop() that decrements the semaphore value. We also specify the
IPC_NOWAIT flag to avoid blocking in case the event is already in the signaled
state. If the semaphore value is zero, then the
semop() call simply fails with EA-
GAIN
, which means that Set() can be called multiple times without any unex-
pected side effects. The
Reset() method works almost as simply, but uses two
operations. The first operation checks whether the event is currently in signaled
state using the
IPC_NOWAIT flag. In case the semaphore value is zero, the first
operation succeeds and performs the second operation, which increments the val-
ue. In case the event is already reset, the semaphore value is already one, and the
first operation fails with
EAGAIN. In this case, the second operation is not execut-
ed, which ensures the coherence of our event status in the semaphore.
The implementation of the
Wait() method for our semaphore-based event is
also quite easy. Again, we have three different scenarios, depending on the speci-
fied timeout value. In order to check whether the event is in signaled state, we
use
semop() with either one or two operations, depending on whether the event
is a manual reset event. The first operation simply checks whether the semaphore
value equals zero, with or without (zero or infinite timeout specified, respective-
ly) using the
IPC_NOWAIT flag. If we are not using a manual reset event, we in-
crement the semaphore value after testing for zero, thus setting the state back to
nonsignaled. This is almost the same trick we used in the
Reset() method, again
using the flexibility and power of
semop(). Some systems also support a timed