locked
CreateTimerQueueTimer -- parameter is not passed? RRS feed

  • Question

  • Hello all,

    I am using CreateTimerQueueTimer() to have a callback function execute once after a certain amount of time has passed:
    CreateTimerQueueTimer(&hTimer,
    NULL,
    (WAITORTIMERCALLBACK) DeleteSubscription,
    &id,
    timeMillis,
    0,
    0);
    where id is a long value. In the DeleteSubscription() method I do *(long *)lpParam to get the sent id again.

    It seems like the parameter I am passing does not make it "safely" to the callback function DeleteSubscription, as it simply has a random value when I access it there. Should id be a global variable instead? Or is there something I am doing wrong?

    (Or, more generally: perhaps there is another way to execute certain actions after certain amounts of time have passed? I tried the CreateTimerQueueTimer approach to avoid having a thread which would wait for multiple waitable timers and do something every time one elapsed, but maybe this was a bad decision)

    Thank you in advance!
    Wednesday, February 24, 2010 4:47 PM

Answers

  • > *ETA: I am pretty sure by now the problem is that the value I am passing
    > is not visible anymore by the time DeleteSubscription() is called (I
    > call CreateTimerQueueTimer() in a method of a class).

    OK, if you're passing a pointer to a stack based variable then it's
    unlikely that the context will still be the same when the callback is
    called. A common method is to allocate on the heap what you need and
    pass the pointer to it. The callback can then access it - and free the
    storage.

    Dave
    • Marked as answer by AC Grama Wednesday, February 24, 2010 5:48 PM
    Wednesday, February 24, 2010 5:46 PM

All replies

  • > CreateTimerQueueTimer(&hTimer,
    > NULL,
    > (WAITORTIMERCALLBACK) DeleteSubscription,

    Remove that cast.
    Why have you got it - doesn't it build without it?

    If I'm guessing right, the source of your problem is that you've not
    declared the callback correctly.

    Dave
    Wednesday, February 24, 2010 4:51 PM
  • ETA: I am pretty sure by now the problem is that the value I am passing is not visible anymore by the time DeleteSubscription() is called (I call CreateTimerQueueTimer() in a method of a class). If I have to pass a global variable, I'm not sure it's worth doing it like this anymore in my app.
    However, I would appreciate if someone could confirm if my usage (as described below) is correct -- thank you!



    Thanks for the fast answer! I had the cast because the CreateTimerQueueTimer example (http://msdn.microsoft.com/en-us/library/ms687003%28VS.85%29.aspx) was defined like that.
    It builds without it, indeed!

    However, I still have the problem. My callback function:


    VOID CALLBACK DeleteSubscription(PVOID lpParam, BOOLEAN TimerOrWaitFired){
    ....
        printf("%d\n", *(long *)lpParam);
    ....
    }
    Maybe I misunderstood something: my idea was that I define with CreateTimerQueueTimer() a timer which would automatically execute DeleteSubscription() once after the given period timeMillis has elapsed. Is this how it is supposed to work?

    --Cristina.
    Wednesday, February 24, 2010 4:59 PM
  • > *ETA: I am pretty sure by now the problem is that the value I am passing
    > is not visible anymore by the time DeleteSubscription() is called (I
    > call CreateTimerQueueTimer() in a method of a class).

    OK, if you're passing a pointer to a stack based variable then it's
    unlikely that the context will still be the same when the callback is
    called. A common method is to allocate on the heap what you need and
    pass the pointer to it. The callback can then access it - and free the
    storage.

    Dave
    • Marked as answer by AC Grama Wednesday, February 24, 2010 5:48 PM
    Wednesday, February 24, 2010 5:46 PM
  • Thanks a lot!
    --Cristina.
    Wednesday, February 24, 2010 5:47 PM
  • 
    AC Grama wrote:
    > I am using CreateTimerQueueTimer() to have a callback function execute once after a certain amount of time has passed:
    >
    > CreateTimerQueueTimer(&hTimer,
    > NULL,
    > (WAITORTIMERCALLBACK) DeleteSubscription,
    > &id,
    > timeMillis,
    > 0,
    > 0);
    > where id is a long value. In the DeleteSubscription() method I do *(long *)lpParam to get the sent id again.
     
    Just pass id directly as a parameter, rather than by pointer. Then you won't have lifetime issues.
     
    CreateTimerQueueTimer(..., (PVOID)id, ...);
     
    In the callback:
     
    long id = (long)lpParam;

    --
    Igor Tandetnik
    Friday, February 26, 2010 12:53 PM