See *new* threadsafe implementation further down!
Old implementation:
Code: Select all
Structure SimpleTimer
delay.i
*variable
EndStructure
Procedure SimpleTimer_Thread(*simpletimer.SimpleTimer)
delay=*simpletimer\delay
*variable=*simpletimer\variable
*simpletimer\delay=0 ;We have copied our values, signal SimpleTimer()
Delay(delay)
PokeI(*variable,delay)
EndProcedure
Procedure SimpleTimer(delay,*variable)
Static simpletimer.SimpleTimer
simpletimer\delay=delay
simpletimer\variable=*variable
CreateThread(@SimpleTimer_Thread(),@simpletimer)
Repeat ;Wait until the thread signal us back.
Delay(1)
Until simpletimer\delay=0 ;Thread is setup and ready, we may continue.
EndProcedure
Code: Select all
delay.l=0
SimpleTimer(10000,@delay)
when 10 seconds has passed, the SimpleTimer thread
will get out of it's delay/wait, and set the referenced (@delay) variable
to the same value as was given at timerstart.
As you can see SimpleTimer uses a static structure to pass the delay and variable pointer,
this is needed since the delay/wait is prformed in a seperate thread.
To avoid thread issues the structure is only used a fraction of a second to
pass the procedure arguments.
So unless you start a lot of timers at the exact same time,
SimpleTimer should be ok to use.
SimpleTimer is not intended for timecritical stuff,
but it is rather nice for other things:
Time delayed Splash screens,
popup timeouts,
events in games (like weather change, music change, sfx)
events in programs (autosaves, network check, memory check, etc)
This timer should also be platform independent,
so Windows, Linux, Mac and Amiga should all be able to use SimpleTimer.
There is no need to kill the timer as it dies on it's own.
One thread will be spawned per timer you use,
but as these will be delay/waiting threads, resource use should be very low.
The advantage of the variable passed as a reference with @
is that the delay/wait thread can set this variable to the waited value.
Thus you can do super simple checks in the program mainloop,
like if you reuse the "timer" maybe instead of setting delay2=0 (see below)
One could instead do that but also set a new timer tied to delay2,
thus reuse the delay2 variable.
Incomplete Example:
Code: Select all
delay=0
SimpleTimer(10000,@delay)
delay2=0
SimpleTimer(5000,@delay2)
Repeat
event=WindowEvent()
If event
gadget=EventGadgetID()
If gadget=#Gadget_Splash
If delay2<>0 : Debug "5 sec" : delay2=0 : EndIf
If EventType()=#PB_EventType_LeftClick : event=#PB_Event_CloseWindow : EndIf
EndIf
EndIf
Delay(1)
If delay<>0 : event=#PB_Event_CloseWindow : EndIf ;no need to set delay=0 here as we'll quit anyway
Until event=#PB_Event_CloseWindow
behaviour/use is same as above so this is a drop in replacement.
Threadsafe implementation:
Code: Select all
Procedure SimpleTimer_Thread(*simpletimer_mem)
Delay(PeekI(*simpletimer_mem))
PokeI(PeekI(*simpletimer_mem+4),PeekI(*simpletimer_mem))
FreeMemory(*simpletimer_mem)
EndProcedure
Procedure SimpleTimer(timeout,*variable)
*simpletimer_mem=AllocateMemory(SizeOf(Integer))
If *simpletimer_mem
PokeI(*simpletimer_mem,timeout)
PokeI(*simpletimer_mem+SizeOf(integer),*variable)
If CreateThread(@SimpleTimer_Thread(),*simpletimer_mem)
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
(memory allocation failed, or starting thread failed)
Have fun folks, and hope this was usefull to some

And if any major flaws in this SimpleTimer, or if you got improvements by all means post here.