Skip to content

Instantly share code, notes, and snippets.

@flowerinthenight
Last active July 8, 2019 08:24
Show Gist options
  • Save flowerinthenight/48d81f079d64dabbad7fa80928159461 to your computer and use it in GitHub Desktop.
Save flowerinthenight/48d81f079d64dabbad7fa80928159461 to your computer and use it in GitHub Desktop.
Using thread APC as FIFO queue to avoid using explicit locking/synchronization when enqueueing/dequeueing.
#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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment