#include #include #include #include static LONG count = 0; static void CALLBACK test_WorkCallback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work) { printf("Hello %s: %03" PRId32 " (thread: 0x%08" PRIX32 ")\n", (char*)context, InterlockedIncrement(&count), GetCurrentThreadId()); for (int index = 0; index < 100; index++) { BYTE a[1024]; BYTE b[1024]; BYTE c[1024] = { 0 }; FillMemory(a, ARRAYSIZE(a), 0xAA); FillMemory(b, ARRAYSIZE(b), 0xBB); CopyMemory(c, a, ARRAYSIZE(a)); CopyMemory(c, b, ARRAYSIZE(b)); } } static BOOL test1(void) { PTP_WORK work = NULL; printf("Global Thread Pool\n"); work = CreateThreadpoolWork(test_WorkCallback, "world", NULL); if (!work) { printf("CreateThreadpoolWork failure\n"); return FALSE; } /** * You can post a work object one or more times (up to MAXULONG) without waiting for prior * callbacks to complete. The callbacks will execute in parallel. To improve efficiency, the * thread pool may throttle the threads. */ for (int index = 0; index < 10; index++) SubmitThreadpoolWork(work); WaitForThreadpoolWorkCallbacks(work, FALSE); CloseThreadpoolWork(work); return TRUE; } static BOOL test2(void) { BOOL rc = FALSE; PTP_POOL pool = NULL; PTP_WORK work = NULL; PTP_CLEANUP_GROUP cleanupGroup = NULL; TP_CALLBACK_ENVIRON environment; printf("Private Thread Pool\n"); if (!(pool = CreateThreadpool(NULL))) { printf("CreateThreadpool failure\n"); return FALSE; } if (!SetThreadpoolThreadMinimum(pool, 4)) { printf("SetThreadpoolThreadMinimum failure\n"); goto fail; } SetThreadpoolThreadMaximum(pool, 8); InitializeThreadpoolEnvironment(&environment); SetThreadpoolCallbackPool(&environment, pool); cleanupGroup = CreateThreadpoolCleanupGroup(); if (!cleanupGroup) { printf("CreateThreadpoolCleanupGroup failure\n"); goto fail; } SetThreadpoolCallbackCleanupGroup(&environment, cleanupGroup, NULL); work = CreateThreadpoolWork(test_WorkCallback, "world", &environment); if (!work) { printf("CreateThreadpoolWork failure\n"); goto fail; } for (int index = 0; index < 10; index++) SubmitThreadpoolWork(work); WaitForThreadpoolWorkCallbacks(work, FALSE); rc = TRUE; fail: if (cleanupGroup) { CloseThreadpoolCleanupGroupMembers(cleanupGroup, TRUE, NULL); CloseThreadpoolCleanupGroup(cleanupGroup); DestroyThreadpoolEnvironment(&environment); /** * See Remarks at * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682043(v=vs.85).aspx If there * is a cleanup group associated with the work object, it is not necessary to call * CloseThreadpoolWork ! calling the CloseThreadpoolCleanupGroupMembers function releases * the work, wait, and timer objects associated with the cleanup group. */ #if 0 CloseThreadpoolWork(work); // this would segfault, see comment above. */ #endif } CloseThreadpool(pool); return rc; } int TestPoolWork(int argc, char* argv[]) { WINPR_UNUSED(argc); WINPR_UNUSED(argv); if (!test1()) return -1; if (!test2()) return -1; return 0; }