Background: As described in this article, Designing Applications for High Performance:
Consider using
PostQueueCompletionStatus
rather thanSetEvent
API. The latter boosts the target thread’s priority by 1 which may cause it to preempt something else.
I am working in C on Windows, and I'd like to replace signalling in a producer/consumer fifo from SetEvent
/WaitForSingleObject
to IO Completion Ports.
The reason is that I want the producer thread to be a background/low priority thread, but SetEvent
always boosts the consumer thread and very often suspends my producer thread, which I would like to avoid to meet certain latency requirements.
Instrumentation for these methods show that I get delays in the order of ~50 microseconds in the producer thread every now and then, right after notifying the consumer thread using SetEvent
, so if this is a cheap replacement I thought I might give it a try.
Short version: I want to switch something like this
void Produce(int some_item)
{
Enqueue(some_item);
SetEvent(hndEvent);
}
void Consume(void)
{
while (true)
{
if (WaitForSingleObject(hndEvent, INFINITE) == WAIT_OBJECT_0)
{
// consume
}
}
}
into something like this I guess:
void Produce(int some_item)
{
Enqueue(some_item);
unsigned long evt = 1; // "item enqueued"
PostQueuedCompletionStatus(hndIOCP, 0, evt, NULL);
}
void Consume(void)
{
while (true)
{
unsigned long evt;
LPOVERLAPPED ovlp;
if (!GetQueuedCompletionStatus(hndIOCP, NULL, &evt, &ovlp, INFINITE))
break;
// consume
}
}
But since I am not using this IOCP for anything other than signaling, what handle should I pass to CreateIoCompletionPort
?
I thought I would simply do something like:
// single thread IOCP
hndIOCP = CreateIoCompletionPort(NULL, NULL, 0, 1);
but it just returns NULL.
I found the answer, I missed the following part in the documentation for CreateIoCompletionPort
.
The first parameter is FileHandle
, and if not used it has to be set to INVALID_HANDLE_VALUE
instead of zero.
FileHandle [in]
An open file handle or
INVALID_HANDLE_VALUE
.
The handle must be to an object that supports overlapped I/O.
If a handle is provided, it has to have been opened for overlapped I/O completion. For example, you must specify the
FILE_FLAG_OVERLAPPED
flag when using theCreateFile
function to obtain the handle.If
INVALID_HANDLE_VALUE
is specified, the function creates an I/O completion port without associating it with a file handle. In this case, theExistingCompletionPort
parameter must beNULL
and theCompletionKey
parameter is ignored.