Friday, November 13, 2009

Example: A Threshold Barrier Object









Example: A Threshold Barrier Object


Suppose that you wish to have the worker threads wait until there are enough workers to form a work crew so that work can proceed. Once the threshold is reached, all the workers start operation and, if any other workers arrive later, they do not wait. This problem can be solved by creating a threshold barrier compound object.


Program 10-1 and 10-2 show the implementation of the three functions that support the threshold barrier compound object. Two of the functions, CreateThresholdBarrier and CloseThresholdBarrier, manage a THB_HANDLE, which is similar to the handles that we have used all along for kernel objects. The threshold number of threads is a parameter to CreateThresholdBarrier.


Program 10-1 shows the appropriate part of the header file, SynchObj.h, while Program 10-2 shows the implementation of the three functions. Notice that the barrier object has a mutex, an event, a counter, and a threshold. The condition variable predicate is documented in the header filethat is, the event is to be set exactly when the count is greater than or equal to the threshold.


Program 10-1. SynchObj.h: Part 1Threshold Barrier Definitions



/* Chapter 10. Compound synchronization objects. */

#define CV_TIMEOUT 50 /* Tunable parameter for the CV model. */

/* THRESHOLD BARRIER -- TYPE DEFINITION AND FUNCTIONS. */
typedef struct THRESHOLD_BARRIER_TAG { /* Threshold barrier. */
HANDLE b_guard; /* Mutex for the object. */
HANDLE b_broadcast; /* Manual-reset evt: b_count >= b_threshold. */
volatile DWORD b_destroyed; /* Set when closed. */
volatile DWORD b_count; /* # of threads at the barrier. */
volatile DWORD b_threshold; /* Barrier threshold. */
} THRESHOLD_BARRIER, *THB_HANDLE;

/* Error values. */
#define SYNCH_OBJ_NOMEM 1 /* Unable to allocate resources. */
#define SYNCH_OBJ_BUSY 2 /* Object is in use and cannot be closed. */
#define SYNCH_OBJ_INVALID 3 /* Object is no longer valid. */

DWORD CreateThresholdBarrier (THB_HANDLE *, DWORD /* Threshold. */);
DWORD WaitThresholdBarrier (THB_HANDLE);
DWORD CloseThresholdBarrier (THB_HANDLE);



Program 10-2 now shows the implementation of the three functions. A test program, testTHB.c, is included on the book's Web site. Notice how the WaitThresholdBarrier function contains the familiar condition variable loop. Also notice that the wait function not only waits on the event but also signals the event using PulseEvent. The previous producer/consumer discussion assumed that distinct thread functions were involved.


Finally, the condition variable predicate is, in this case, persistent. Once it becomes true, it will never change, so there is no danger from signaling the event more than once.


Program 10-2. ThbObject.c: Implementing the Threshold Barrier



/* Chapter 10. Program 102. */
/* Threshold barrier compound synch objects library. */

#include "EvryThng.h"
#include "synchobj.h"

/*********************************/
/* THRESHOLD BARRIER OBJECTS */
**********************************/

DWORD CreateThresholdBarrier (THB_HANDLE *pthb, DWORD b_value)
{
THB_HANDLE hthb;
/* Initialize a barrier object. Full error testing is on Web site.*/
hthb = malloc (sizeof (THRESHOLD_BARRIER));
hthb->b_guard = CreateMutex (NULL, FALSE, NULL);
hthb->b_broadcast = CreateEvent (NULL, FALSE /* Auto-reset. */,
FALSE, NULL);

hthb->b_threshold = b_value;
hthb->b_count = 0;
hthb->b_destroyed = 0;
*pthb = hthb;
return 0;
}

DWORD WaitThresholdBarrier (THB_HANDLE thb)
{
/* Wait for the specified number of threads to reach */
/* the barrier, then set the event. */
if (thb->b_destroyed == 1) return SYNCH_OBJ_INVALID;
WaitForSingleObject (thb->b_guard, INFINITE);
thb->b_count++; /* A new thread has arrived. */
while (thb->b_count < thb->b_threshold) {
SignalObjectAndWait (thb->b_guard, thb->b_broadcast,
INFINITE, FALSE);
WaitForSingleObject (thb->b_guard, INFINITE);
}
PulseEvent (thb->b_broadcast);
/* Broadcast CV model, releasing all waiting threads. */
ReleaseMutex (thb->b_guard);
return 0;
}

DWORD CloseThresholdBarrier (THB_HANDLE thb)
{
/* Destroy the component mutex and event. */
/* Be certain that no thread is waiting on the object. */
if (thb->b_destroyed == 1) return SYNCH_OBJ_INVALID;
WaitForSingleObject (thb->b_guard, INFINITE);
if (thb->b_count < thb->b_threshold) {
ReleaseMutex (thb->b_guard);
return SYNCH_OBJ_BUSY;
}
ReleaseMutex (thb->b_guard);
CloseHandle (thb->b_guard);
CloseHandle (thb->b_broadcast);
free (thb);
return 0;
}



Comments on the Threshold Barrier Implementation


The threshold barrier object implemented here is limited for simplicity. In general, we would want to emulate Windows objects by:


  • Allowing the object to have security attributes (Chapter 15)

  • Allowing the object to be named

  • Permitting multiple "handles" on the object and not destroying it until the reference count is 0

  • Allowing the object to be shared between processes


The Web site contains a full implementation of one such object, a multiple wait semaphore, and the techniques used there can then be used for any of the objects in this chapter.









    No comments: