A C++ class that provides a Win32 semaphore with priority levels.
by
Thomas Becker
thomas@styleadvisor.com
COPYRIGHT (C) 1998 Thomas BeckerPERMISSION NOTICE:
PERMISSION TO USE, COPY, MODIFY, AND DISTRIBUTE THIS SOFTWARE FOR ANY PURPOSE AND WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT ALL COPIES ARE ACCOMPANIED BY THE COMPLETE MACHINE-READABLE SOURCE CODE, ALL MODIFIED FILES CARRY PROMINENT NOTICES AS TO WHEN AND BY WHOM THEY WERE MODIFIED, THE ABOVE COPYRIGHT NOTICE, THIS PERMISSION NOTICE AND THE NO-WARRANTY NOTICE BELOW APPEAR IN ALL SOURCE FILES AND IN ALL SUPPORTING DOCUMENTATION.
NO-WARRANTY NOTICE:
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.
After construction, a CPrioritySemaphore object must be properly intialized with the Create() member function. In addition to the initial and maximal count of the semaphore, the caller must specify the number of priority levels that the semaphore object will support.
The Release() member function increments the count of the semphore object just like the Win32 function ReleaseSemaphore().
The additional functionality of the priority semaphore is provided by the Wait() member function. In addition to the wait timeout, which can be a finite number of milliseconds or the Win32 constant INFINITE, Wait() takes as an argument the desired priority level, where priorities range from zero to one less than the number of priority levels. When the current count of the semaphore object is greater than zero, the object behaves exactly like a Win32 semaphore: the wait operation completes immediately, and the current count of the semaphore decreases by one. When the count has dropped down to zero, Wait() will block just like Win32's WaitForSingleObjects() would. However, when more than one thread is blocking on a call to Wait() and the semaphore object becomes signalled, i.e., some thread calls the Release() member function, the semaphore will now release the waiting threads in the order of their wait priorities. More precisely, threads are released according to the round robin scheme: As long as there are threads waiting with priority level x, no thread on a priority level less than x can be released, regardless of the order in which the threads arrived.
CPrioritySemaphore provides a function GetNumWaitingThreads() which returns the current number of threads waiting with a given priority. This function must not be used for synchronization purposes. (See the documentation of GetNumWaitingThreads() for an explanation.) The purpose of this function is to help avoid backlogs of threads that are blocking on Wait() with low priority levels. Before an application accepts clients with higher priority levels, it may wish to check the backlog of threads with lower priorities and reject the client with higher priority if that backlog exceeds an acceptable limit.
Construction | |
---|---|
CPrioritySemaphore | Constructs a CPrioritySemaphore object. |
Operations | |
Create | Creates and initializes the priority semaphore. |
Wait | Blocks until the semaphore count is greater than zero and all threads waiting with higher semaphore priority have been released. |
Release | Releases the semaphore. |
GetNumWaitingThreads | Returns the total number of threads that are currently blocking on the Wait() member function. Do not use this function for synchronization purposes. |
CPrioritySemaphore::CPrioritySemaphore();
BOOL CPrioritySemaphore::Create( LONG lNumPriorityLevels, // number of priority levels LONG lInitialCount, // initial count LONG lMaximalCount // maximal count );
If the calling program's new handler is such that a failed new throws an exception, the function will rethrow such exceptions after cleaning up.
DWORD CPrioritySemaphore::Wait( LONG lWaitPriority, // wait priority level DWORD dwMillisecondsTimeout /* = INFINITE, timeout in milliseconds
Note that this can lead to "starving" of threads. If there are threads blocking with priority level x, and they keep arriving at a rate that is greater than or equal to the rate at which they are released, then no thread that is waiting with a priority level less than x can be released.
void CPrioritySemaphore::Release( LONG lReleaseCount, // amount to add to the current count LPLONG lpPreviousCount) // memory location to receive previous count );
void CPrioritySemaphore::GetNumWaitingThreads( LONG lWaitPriority // priority level to check );
The purpose of this function is to help avoid backlogs of threads that are blocking on Wait() with low priority levels. Before an application accepts clients with higher priority levels, it may wish to check the backlog of threads with lower priorities and reject the client with higher priority if that backlog exceeds an acceptable limit.