You also might try this. It's a fast semaphore I've posted before
with the bug in processCancels() fixed hopefully. You can try
a straight forward producers/consumers solution with it and see
how it works out.
Joe Seigh
---------------------------------------------------------
#ifndef QSYNC_H
#define QSYNC_H
#ifdef __cplusplus
extern "C" {
#endif
//----------------------------------------------------------------------------
// QSem
//----------------------------------------------------------------------------
typedef struct {
LONG count;
LONG cancel; // deferred cancel count
HANDLE hSem;
} qsem_t;
extern void InitializeQSem(qsem_t * qs, int z);
extern void DeleteQSem(qsem_t * qs);
extern DWORD WaitForQSem(qsem_t * qs, DWORD dwTimeout);
extern void ReleaseQSem(qsem_t * qs);
#ifdef __cplusplus
}
#endif
#endif // QSYNC_H
/*-*/
---------------------------------------------------------
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <winbase.h>
#include <qsync.h>
//----------------------------------------------------------------------------
//
//
// increment count by min(cancelCount, -(count)) iff count < 0
//----------------------------------------------------------------------------
void processCancels(qsem_t * qs, LONG cancelCount) {
LONG temp2, temp3, temp4, temp5;
if (cancelCount > 0) {
temp2 = qs->count;
while (temp2 < 0) {
temp3 = 0; // unprocessed cancels
temp4 = cancelCount + temp2; // new count
if (temp4 > 0) {
temp3 = temp4; // unprocessed cancels
temp4 = 0; // new count
}
temp5 = temp2;
if ((temp2 = InterlockedCompareExchange(&(qs->count), temp4, temp2)) == temp5)
break;
}
if (temp3 > 0)
InterlockedExchangeAdd(&(qs->cancel), temp3);
}
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void InitializeQSem(qsem_t * qs, int z) {
qs->count = z;
qs->cancel = 0;
qs->hSem = CreateSemaphore(NULL, 0, 999999, NULL);
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void DeleteQSem(qsem_t * qs) {
CloseHandle(qs->hSem);
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
DWORD WaitForQSem(qsem_t * qs, DWORD dwTimeout) {
DWORD rc = WAIT_OBJECT_0;
if (InterlockedDecrement(&(qs->count)) < 0) {
if ((rc = WaitForSingleObject(qs->hSem, dwTimeout)) != WAIT_OBJECT_0) {
// uncomment 1 and only one of the next 2 lines.
InterlockedIncrement(&(qs->cancel));
//processCancels(qs, 1);
}
}
return rc;
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void ReleaseQSem(qsem_t * qs) {
if (qs->cancel > 0 && qs->count < 0)
processCancels(qs, InterlockedExchange(&(qs->cancel), 0));
if (InterlockedIncrement(&(qs->count)) <= 0)
ReleaseSemaphore(qs->hSem, 1, NULL);
}
/*-*/
---------------------------------------------------------