The Windows Processes and Threads 26

 

 

 

 

 

Using the Thread Pool Functions Program Example (Vista/Server 2008)

 

The following working example creates a custom thread pool, creates a work item and a thread pool timer, and associates them with a cleanup group. The pool consists of one persistent thread. It demonstrates the use of the following thread pool functions:

 

  1. CloseThreadpool()
  2. CloseThreadpoolCleanupGroup()
  3. CloseThreadpoolCleanupGroupMembers()
  4. CloseThreadpoolWait()
  5. CloseThreadpoolWork()
  6. CreateThreadpool()
  7. CreateThreadpoolCleanupGroup()
  8. CreateThreadpoolTimer()
  9. CreateThreadpoolWait()
  10. CreateThreadpoolWork()
  11. InitializeThreadpoolEnvironment()
  12. SetThreadpoolCallbackCleanupGroup()
  13. SetThreadpoolCallbackPool()
  14. SetThreadpoolThreadMaximum()
  15. SetThreadpoolThreadMinimum()
  16. SetThreadpoolTimer()
  17. SetThreadpoolWait()
  18. SubmitThreadpoolWork()
  19. WaitForThreadpoolWaitCallbacks()

 

For the above mentioned functions the following info should be applied.

 

Minimum supported client:     Windows Vista

Minimum supported server: Windows Server 2008

Header:           Winbase.h (include Windows.h)

Library:           Kernel32.lib

DLL:   Kernel32.dll

 

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

 

Using the Thread Pool Functions Program Example (Vista/Server 2008): Creating new Win32 C++ console application project in Visual C++ .NET

 

Then, add the source file and give it a suitable name.

 

Using the Thread Pool Functions Program Example (Vista/Server 2008): Adding new C++ source file for C++ source code to the existing C++ project

 

Next, add the following source code.

 

// This just a program skeleton

#include <windows.h>

#include <stdio.h>

 

// Thread pool wait callback function template

void CALLBACK MyWaitCallback(

    PTP_CALLBACK_INSTANCE Instance,

    PVOID                 Parameter,

    PTP_WAIT              Wait,

    TP_WAIT_RESULT        WaitResult

    )

{

      wprintf(L"MyWaitCallback() - Wait callback is over...\n");

      // Do something when the wait is over

}

 

// Thread pool timer callback function template

void CALLBACK MyTimerCallback(

    PTP_CALLBACK_INSTANCE Instance,

    PVOID                 Parameter,

    PTP_TIMER             Timer

    )

{

    wprintf(L"MyTimerCallback() - Timer fireddddd.....\n");

    // Do something when the timer fires

}

 

// This is the thread pool work callback function.

// The callback demonstrates correct behavior when changing the

// state of the thread inside the callback function.

//

// Any changes to the thread state must be restored to original

// before exiting the callback routine.

void CALLBACK MyWorkCallback(

    PTP_CALLBACK_INSTANCE Instance,

    PVOID                 Parameter,

    PTP_WORK              Work

    )

{

    BOOL bRet = FALSE;

    DWORD dwPriorityOriginal = 0;

 

    // Record the original thread priority

    dwPriorityOriginal = GetThreadPriority(GetCurrentThread());

 

    if (dwPriorityOriginal == THREAD_PRIORITY_ERROR_RETURN)

      {

        wprintf(L"GetThreadPriority() failed, error is %u\n", GetLastError());

        return;

    }

 

    // Increase the priority of the thread pool thread

    bRet = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);

 

    if (bRet == FALSE)

      {

        wprintf(L"SetThreadPriority() failed, error is %u\n", GetLastError());

        return;

    }

 

    // Perform tasks at increased priority

      {

            wprintf(L"Performing task at the higher level of priority...\n");

      }

     

      // Restore thread state by resetting the original priority

      bRet = SetThreadPriority(GetCurrentThread(), dwPriorityOriginal);

     

      // If restore fails, maybe retry or throw an exception.  Otherwise,

      // the thread will continue to execute other work items at increased priority.

      if (bRet == FALSE)

      {

            wprintf(L"Fatal Error! SetThreadPriority() failed, error is %u\n", GetLastError());

            return;

      }

    return;

}

 

void DemoCleanupPersistentWorkTimer()

{

    BOOL bRet = FALSE;

    PTP_WORK work = NULL;

    PTP_TIMER timer = NULL;

    PTP_POOL pool = NULL;

    PTP_WORK_CALLBACK workcallback = MyWorkCallback;

    PTP_TIMER_CALLBACK timercallback = MyTimerCallback;

    TP_CALLBACK_ENVIRON CallBackEnviron;

    PTP_CLEANUP_GROUP cleanupgroup = NULL;

    FILETIME FileDueTime;

    ULARGE_INTEGER ulDueTime;

    UINT rollback = 0;

 

    InitializeThreadpoolEnvironment(&CallBackEnviron);

 

    // Create a custom, dedicated thread pool

    pool = CreateThreadpool(NULL);

 

    if (pool == NULL)

      {

        wprintf(L"CreateThreadpool() failed, error is %u\n", GetLastError());

        goto main_cleanup;

    }

    // pool creation succeeded

    rollback = 1;

 

    // The thread pool is made persistent simply by setting

    // both the minimum and maximum threads to 1.

    SetThreadpoolThreadMaximum(pool, 1);

 

    bRet = SetThreadpoolThreadMinimum(pool, 1);

 

    if (bRet == FALSE)

      {

        wprintf(L"SetThreadpoolThreadMinimum() failed, error is %u\n", GetLastError());

        goto main_cleanup;

    }

 

    // Create a cleanup group for this thread pool

    cleanupgroup = CreateThreadpoolCleanupGroup();

 

    if (cleanupgroup == NULL)

      {

        wprintf(L"CreateThreadpoolCleanupGroup() failed, error is %u\n", GetLastError());

        goto main_cleanup;

    }

 

    // Cleanup group creation succeeded

    rollback = 2;

 

    // Associate the callback environment with our thread pool

    SetThreadpoolCallbackPool(&CallBackEnviron, pool);

 

    // Associate the cleanup group with our thread pool

    SetThreadpoolCallbackCleanupGroup(&CallBackEnviron, cleanupgroup, NULL);

 

    // Create work with the callback environment

    work = CreateThreadpoolWork(workcallback, NULL, &CallBackEnviron);

 

    if (work == NULL)

      {

        wprintf(L"CreateThreadpoolWork() failed, error is %u\n", GetLastError());

        goto main_cleanup;

    }

    // Creation of work succeeded

    rollback = 3;

 

    // Submit the work to the pool. Because this was a pre-allocated

    // work item (using CreateThreadpoolWork), it is guaranteed to execute

    SubmitThreadpoolWork(work);

 

    // Create a timer with the same callback environment

    timer = CreateThreadpoolTimer(timercallback, NULL, &CallBackEnviron);

 

    if (timer == NULL)

      {

        wprintf(L"CreateThreadpoolTimer() failed, error is %u\n", GetLastError());

        goto main_cleanup;

    }

    // Timer creation succeeded

    rollback = 4;

 

    // Set the timer to fire in one second

    ulDueTime.QuadPart = (LONGLONG) -(1 * 10 * 1000 * 1000);

    FileDueTime.dwHighDateTime = ulDueTime.HighPart;

    FileDueTime.dwLowDateTime  = ulDueTime.LowPart;

 

    SetThreadpoolTimer(timer, &FileDueTime, 0, 0);

 

    // Delay for the timer to be fired

    Sleep(1500);

 

    // Wait for all callbacks to finish.

    // CloseThreadpoolCleanupGroupMembers also calls the cleanup

    // functions for all the individual objects in the specified

    // cleanup group.

    CloseThreadpoolCleanupGroupMembers(cleanupgroup, FALSE, NULL);

 

    // Already cleaned up the work item with the

    // CloseThreadpoolCleanupGroupMembers, so set rollback to 2.

    rollback = 2;

    goto main_cleanup;

 

main_cleanup:

    // Clean up any individual pieces manually

    // Notice the fall through structure of the switch.

    // Clean up in reverse order.

    switch (rollback)

      {

        case 4:

        case 3:

            // Clean up the cleanup group members

            CloseThreadpoolCleanupGroupMembers(cleanupgroup, FALSE, NULL);

        case 2:

            // Clean up the cleanup group

            CloseThreadpoolCleanupGroup(cleanupgroup);

        case 1:

            // Clean up the pool

            CloseThreadpool(pool);

        default:

            break;

    }

    return;

}

 

void DemoNewRegisterWait()

{

    PTP_WAIT Wait = NULL;

    PTP_WAIT_CALLBACK waitcallback = MyWaitCallback;

    HANDLE hEvent = NULL;

    UINT i = 0;

    UINT rollback = 0;

 

    // Create an auto-reset event

    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

 

    if (hEvent == NULL)

      {

        // Error Handling

        wprintf(L"CreateEvent() failed, error is %u\n", GetLastError());

        return;

    }

 

    // CreateEvent() succeeded

    rollback = 1;

 

    Wait = CreateThreadpoolWait(waitcallback, NULL, NULL);

 

    if(Wait == NULL)

      {

        wprintf(L"CreateThreadpoolWait() failed, error is %u\n", GetLastError());

        goto new_wait_cleanup;

    }

    // CreateThreadpoolWait succeeded

    rollback = 2;

 

    // Need to re-register the event with the wait object

    // each time before signaling the event to trigger the wait callback

    for (i = 0; i < 5; i ++)

      {

        SetThreadpoolWait(Wait, hEvent, NULL);

 

        SetEvent(hEvent);

 

        // Delay for the waiter thread to act if necessary

        Sleep(500);

 

        // Block here until the callback function is done executing

        WaitForThreadpoolWaitCallbacks(Wait, FALSE);

    }

 

new_wait_cleanup:

    switch (rollback)

      {

        case 2:

            // Unregister the wait by setting the event to NULL

            SetThreadpoolWait(Wait, NULL, NULL);

            // Close wait

            CloseThreadpoolWait(Wait);

        case 1:

            // Close event

            CloseHandle(hEvent);

        default:

            break;

    }

    return;

}

 

int wmain(int argc, WCHAR **argv)

{

    DemoNewRegisterWait();

    DemoCleanupPersistentWorkTimer();

    return 0;

}

 

Build and run the project. The following is the sample output when run on Windows XP Pro SP2. We need Windows Vista/Windows Server 2008.

 

Using the Thread Pool Functions Program Example (Vista/Server 2008): A sample console program output in action showing error message which indicates this program should be run on Windows Vista/Server 2008 or above

 

The following section is left for you to be explored: Process and Thread Reference.

 

 

 

< Processes & Threads 25 | Win32 Process & Thread Programming | Win32 Programming | Character Mode Application Win32 Programming >