lightning
lightning

Reputation: 37

Using Timer with Windows Thread Pool

I have written the following program which It should print something for 10th time. I wanted to use timer and thread pool to implement the following program but this program only show one message and then program will quit.

#include <windows.h>
#include <process.h>
#include <iostream>


// How many seconds we'll display the message box
int g_nSecLeft = 10;

PTP_WORK g_WorkItem = NULL;

VOID CALLBACK WorkerOne(PTP_CALLBACK_INSTANCE arg_instance, PVOID arg_context, PTP_TIMER arg_timer)
{
    std::printf("You have %d seconds to respond", --g_nSecLeft);
}

int main(int argc, char* argv[])
{
    // Create the thread pool timer object
    PTP_TIMER pointer_timer = CreateThreadpoolTimer(WorkerOne, NULL, NULL);

    if (pointer_timer == NULL) 
    {
        std::cout << "Error: something goes wrong." << std::endl;
        return -1;
    }

    // Start the timer in one second to trigger every 1 second
    ULARGE_INTEGER relative_start_time;
    relative_start_time.QuadPart = (LONGLONG)-(10000000); // start in 1 second
    
    FILETIME ft_relative_start_time;
    ft_relative_start_time.dwHighDateTime = relative_start_time.HighPart;
    ft_relative_start_time.dwLowDateTime = relative_start_time.LowPart;
    
    SetThreadpoolTimer(pointer_timer, &ft_relative_start_time, 1000, 0);
    
    if (IsThreadpoolTimerSet(pointer_timer))
    {
        std::cout << "Time has been set." << std::endl;
    }

    WaitForThreadpoolWorkCallbacks(g_WorkItem, FALSE);
    
    return 0;
}

Why it doesn't call the callback function for more than one time?

Upvotes: 1

Views: 756

Answers (2)

catnip
catnip

Reputation: 25398

Calling WaitForThreadpoolWorkCallbacks() is the wrong thing to do. It waits for work items queued via CreateThreadpoolWork() to complete, but you're not queuing any work items, so WaitForThreadpoolWorkCallbacks() returns immediately and your program just exits.

Since you've got nothing better to do, you might as well just call Sleep() in the main thread. Or, you can have the main thread create an event object with CreateEvent(), then signal that event in your timer callback, and have the main thread wait for the event to be signaled.

Upvotes: 1

RbMm
RbMm

Reputation: 33784

you can use for instance next code

struct TimerData 
{
    HANDLE hEvent = CreateEvent(0, 0, 0, 0);
    LONG n;

    ~TimerData()
    {
        if (hEvent) CloseHandle(hEvent);
    }

    TimerData(ULONG n) : n(n) {}

    static VOID CALLBACK TimerCallback(
        __inout      PTP_CALLBACK_INSTANCE /*Instance*/,
        __inout_opt  PVOID Context,
        __inout      PTP_TIMER Timer
        )
    {
        DbgPrint("TimerCallback(%d)\n", reinterpret_cast<TimerData*>(Context)->n);
        if (!InterlockedDecrementNoFence(&reinterpret_cast<TimerData*>(Context)->n))
        {
            SetThreadpoolTimer(Timer, 0, 0, 0);
            SetEvent(reinterpret_cast<TimerData*>(Context)->hEvent);
        }
    }
};

void TimerDemo(ULONG n)
{
    if (TimerData* p = new TimerData(n))
    {
        if (p->hEvent)
        {
            if (PTP_TIMER Timer = CreateThreadpoolTimer(TimerData::TimerCallback, p, 0))
            {
                LARGE_INTEGER li = { (ULONG)-10000000, -1};
                SetThreadpoolTimer(Timer, (PFILETIME)&li, 1000, 0);

                WaitForSingleObject(p->hEvent, INFINITE);
                CloseThreadpoolTimer(Timer);
            }
        }
        delete p;
    }
}

Upvotes: 1

Related Questions