In this way, we can implement a FIFO queue without using explicit locking/synchronization for enqueueing/dequeueing.
For self reference:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
typedef struct _param_t { | |
int code; | |
} param_t; | |
HANDLE hTerm = NULL; // terminate event | |
HANDLE hThr = NULL; // apc thread | |
HANDLE hReady = NULL; // apc thread ready event | |
// This is our FIFO queue thread. | |
DWORD __stdcall InternalApcDispatcher(LPVOID lpData) | |
{ | |
_tprintf(L"[%d] dispatcher started.\n", GetCurrentThreadId()); | |
SetEvent(hReady); | |
while (TRUE) { | |
// All we need to do here is to set this thread to alertable wait to be able to service | |
// user mode APCs. Clients will queue APCs to this thread for servicing. | |
if (WaitForSingleObjectEx(hTerm, INFINITE, TRUE) == WAIT_OBJECT_0) break; | |
} | |
return 0; | |
} | |
// Helper function to add work to our queue. | |
DWORD QueueWork(PAPCFUNC pFunction, ULONG_PTR pData) | |
{ | |
return QueueUserAPC(pFunction, hThr, pData); | |
} | |
// Sample work to be queued. | |
VOID CALLBACK APCProc(_In_ ULONG_PTR dwParam) | |
{ | |
int i = (int)dwParam; | |
_tprintf(L"threadid: %d, data: %d\n", GetCurrentThreadId(), i); | |
} | |
int main() | |
{ | |
hTerm = CreateEvent(NULL, TRUE, FALSE, NULL); | |
hReady = CreateEvent(NULL, TRUE, FALSE, NULL); | |
// create the FIFO queue thread | |
hThr = CreateThread(NULL, 0, InternalApcDispatcher, NULL, 0, NULL); | |
// wait for it to be ready | |
WaitForSingleObject(hReady, INFINITE); | |
// queue 10 work items with index as our data | |
for (int i = 0; i < 10; i++) { | |
QueueWork(APCProc, (ULONG_PTR)i); | |
} | |
// wait a bit to allow APC processing | |
Sleep(3000); | |
// close everything | |
SetEvent(hTerm); | |
CloseHandle(hTerm); | |
CloseHandle(hReady); | |
WaitForSingleObject(hThr, INFINITE); | |
return 0; | |
} |