Click here to Skip to main content
15,881,877 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I using timers to set outputs. Sometime these timers get set to execute within the user_timer_minimum (wich is 10ms). Like this
SetTimer(wnd, 1, delay, (TIMERPROC)SetOutput);
SetTimer(wnd, 2, delay, (TIMERPROC)SetOutput);
delay is 1000.
This two timers is set with same delay and they are both set within 10ms. The result of this is the problem, I want to treat the timers in the same order I set them, first a want timer id 1 to execute then timer id 2. But it is often the other way around. When the timer goes of after 1 second delay it is first timer id 2 and then timer id 1.
Is there a way to control the order of execution in this cases or do I need to calculate and add a small time to be sure they don't execute in the same user_timer_minimum?

I working with a c-program in Windows 10 and VS2019.

What I have tried:

I have started to calculate the order but it feels unnecessarily complicated.
Posted
Updated 30-Oct-22 21:40pm
v2
Comments
11917640 Member 27-Oct-22 7:12am    
So, you have two timers set at the same time and with same period. Why do you need two timers and not one, that makes all actions in the desired order?

No you can never control the order that they will be handled. When you create a timer it is put into a queue that The Windows OS manages. As each time expires the appropriate message is posted to the thread or application queue that owns the timer. But the order that these messages are posted is not controllable. You need to add some code to your timer proc to re-order them as they occur.
 
Share this answer
 
Comments
merano99 28-Oct-22 2:53am    
yes, +5 (some code, like IPC commands like mutex; see my suggestion)
marreoragarn 28-Oct-22 5:05am    
I have started a way to calculate when a certain timer is supposed to execute and if there is another timer (controlling the same hardware) executing the same time, within 10 ms, I adding 30ms delay extra on the second timer to avoid to get the in the wrong order.
The reason is that timers controlling hardware outputs and if they execute in the wrong order the lamp can be turned of when it is supposed to be turned of.
The problem with execution order seems to have come with VS2019, software compiled in VS6 did not had any problems to execute timers in the order they where set.
Richard MacCutchan 28-Oct-22 5:19am    
As other people have suggested, this is not the best design. You only need one timer, and some flag or other mechanism, to decide which path to take when the timer fires.
This makes very little sense to me. You have set two timers with the same period and you want to service them in a particular order. The answer seems obvious: use just one timer and call the two functions from a service function in the order that you want.
 
Share this answer
 
Comments
merano99 28-Oct-22 2:50am    
yes, +5
Rick York 28-Oct-22 10:51am    
Thank you sir.
SetTimer is documented here[^]. Based on that page, the only way to distinguish the timers is to use the WM_TIMER event instead of a callback to a TIMERPROC:
Quote:
The wParam parameter of the WM_TIMER message contains the value of the nIDEvent parameter.
The documentation[^] for a TIMERPROC mentions unnamed parameters. I wouldn't be surprised if the UINT_PTR one was at least intended to be your timer identifier, but it doesn't seem like this was implemented. I think I know why, but it doesn't really matter.

EDIT: Based on what Richard mentioned below, the third parameter to your TIMERPROC should indeed be your original timer identifier.
 
Share this answer
 
v3
Comments
Richard MacCutchan 27-Oct-22 7:55am    
I just tried it and the values are as stated in Windows API Guide: TimerProc Callback Function[^].
Greg Utas 27-Oct-22 8:20am    
Some obscure site has better documentation than MSFT? LOL.
Well, this workaround should do the trick, if you can tolerate a slight delay change:
C
UINT_PTR set_timer(HWND hwnd, UINT_PTR id, UINT elapse, TIMERPROC tproc)
{
  return SetTimer(hwnd, id, (elapse + id), tproc);
}
 
Share this answer
 
Comments
marreoragarn 28-Oct-22 5:10am    
My solution is very much like what you have suggested. I am not done yet but here is how I do:
SetTimer(wnd_main, TIMER_DO_SET + i, delay + Extended_ms, (TIMERPROC)SetOutput);

I calculate the ext like this:
struct _timeb timebuffer;
time_t CurrentTimeS;
unsigned short CurrentTimeMS;
_ftime64_s(&timebuffer);
CurrentTimeS = timebuffer.time;
CurrentTimeMS = timebuffer.millitm;
int delay = IO_data.DO_Run[i].Value ? PimIniStruct.DO[i].DelaySet : PimIniStruct.DO[i].DelayReset;
int val = CurrentTimeS + delay;
if (val == PimIniStruct.DO[DO_No].NextTimeS)
{
if(abs(PimIniStruct.DO[DO_No].NextTimeMS - CurrentTimeMS) < 200)
{
Extended_ms += 3 * USER_TIMER_MINIMUM; // Move the timer to the third time slot
break;
}
}
Like Richard and Rick, I also think that it makes no sense to start two functions with one timer each, if the order is fixed here. Should it still make sense that both functions can run in parallel, one could start threads for this. Because the reason of the order is probably access to data or other resources I would save these places in the threads with mutex semaphores.

Also with two timers it would be necessary to force the order with semaphores or similar, but then the two timers cause more problems than they contribute to the solution.
 
Share this answer
 
v2
The solution I did was simple, I deleting (KillTimer) if we have a timer controlling the same hardware as a later timer execution. So I store the execution time for all timers in me DO_struct, I compare all outputs if they are conflicting with same hardware as the current SetTimer will control. I check if they will execute within 20 ms, if so, I kill the timer that are going to execute first and set the current one as normal. No extension of times etc.

Thanks for solution and ideas.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900