how to do some processing at set time intervals
BlitzMax Forums/BlitzMax Programming/how to do some processing at set time intervals
| ||
| I would like to know in blitz basic (bearing in mind i am new to this software) if there is a way (with an example, which would be nice) of calling a routine at a pre-determined interval. In Liberty basic, this is so so easy, you just use timer 1000, [subroutine] where 1000 is 1000 milliseconds (or 1 second) is it simialr in blitz basic ? I really want to use blitz because it seems much more powerful than liberty basic. |
| ||
| There's BRL.Timer. ... there's also wx.wxTimer ;-) |
| ||
| real timers and event hooks. But beside that no. Above feature looks like a scripting feature, not a feature of a binary code compiled language. |
| ||
SuperStrict
Const TICK_EVENT:Int=69
Function test_function:Object( id:Int,data:Object,context:Object )
Local ev:TEvent=TEvent(data)
Select ev.id
Case TICK_EVENT
Print "Hello World!"
End Select
End Function
Local MY_EVENT:TEvent=CreateEvent(TICK_EVENT)
Local myTimer:TTImer = CreateTimer(1,MY_EVENT)
'Add our hook to the system
AddHook EmitEventHook,test_function
While EventID() <> EVENT_KEYDOWN
PollEvent
EndWhile
although BRL have said CreateEvent should really be internal use only. Not too friendly but does the job... I think. |
| ||
Or a more noob-coder-friendly way:Local myTimer:TTimer = CreateTimer(1) While (Not KeyDown(KEY_ESCAPE)) And (Not AppTerminate()) If myTimer.Ticks() Print "Timer ticked at " + MilliSecs() + " ms!" myTimer._Ticks = 0'reset timer tick counter EndIf Delay 1 Wend |
| ||
| [Oops: doesn't seem to work anymore.] Or try this: Interval system |
| ||
| they are all together as useless as they look like due to the restriction on the amount of timers BM will allow you. You better do a virtual timer system with timed "callbacks" handler object that measures millisecs differences and calls the function (or through reflection as well method) after the given time and removing itself. |
| ||
| @GfK, yep certainly easier but not as 'fire-and-forget'. @Dreamora, all the suggestions answer the question so are not exactly 'useless'. I'd certainly like to see the method you're proposing so an example would be nice. |
| ||
A timer with timed "callbacks" measured in millisecs (of 100 in this case).
SuperStrict
Framework wx.wxApp
Import wx.wxTimer
Import BRL.StandardIO
Type MyApp Extends wxApp
Field timer:MyTimer
Method OnInit:Int()
timer = MyTimer(New MyTimer.Create())
timer.Start(100)
Return True
End Method
End Type
Type MyTimer Extends wxTimer
Field count:Int
Method Notify()
count:+1
Print "Tick (" + count + ")"
If count = 50 Then
End
End If
End Method
End Type
New MyApp.run()
This is only one way of using wxTimer, of course. |
| ||
SuperStrict
Import Datastruct.PriorityQueue
Type TVirtualThread
field nextExecution:int
field functionToCall(data:object)
field data:object
global prioQueue:TPriorityQueue = TPriorityQueue.Create()
global lastCheck:int
function create:TVirtualThread(functionToCall(data:object), data:object, timeToWait:int)
local result:TVirtualThread = new TVirtualThread
result.nextExecution = millisecs() + timeToWait
result.functionToCall = functionToCall
result.data = data
end function
function updateExecution()
if millisecs() - lastCheck < 1 return
local curTime:int = millisecs()
local thread:TVirtualThread = TVirtualThread(prioQueue.top())
while thread.nextExecution < curTime
thread.functionToCall(thread.data)
prioQueue.pop()
thread = TVirtualThread(prioQueue.top())
wend
end function
end type
Datastruct PriorityQueue is a module I wrote myself. It is a high performant priorityqueue implemented with a heap under the hood The code is not tested but should you give an idea of how to do it. With Reflection you could even do objects with method calls using invoke. The only thing you need to do is call TVirtualThread.updateExecution() in your mainloop (using a 1000 hz timer would be kind of worthless I feel) |
| ||
if your function doesn't need to be called at exact to the millisecond precision, you could just check the millisecs() timer in your main loop and call the routine from there.
Local Time:int = Millisecs() + 1000 ' one second later
While Not KeyHit(KEY_ESCAPE)
If Millisecs() >= Time 'Check if second is up
Time :+ 1000 'add another second to time
DoFunction()
End If
Wend |
| ||
| What I did, which only really works if you are running scripts and not normal code, is to do a multitasking scheduler like an o/s would do it, which gets called approximately every millisecond (which depends on execution times) to check that any high-priority scripts get to pre-empt other scripts. Works great for me but again I am actively going and checking on the time which is not the ideal scenario. But then again, the only way to do that properly is to have the hardware force something to happen, like an exception or interrupt which calls upon some kind of interrupt processor code that was pre-installed at a fixed memory address, but at least then this would totally pre-empt everything and tell you the timer ticked exactly when it did. |
| ||
| Poor Robo. His head is going to hurt so much. I suggest TomToad's as an easy to understand solution. |
| ||
| Problem is, tom toads isn't flexible. you can not just run any potential function at a later time ... only hardcoded ones at a given time. It is normally called "Timed Code Execution" and is used for physics updates, network updates and the like. Things that repeatively executed at a given frequency. Not flexible timed, single time function execution. |
| ||
| Did you check your requirements, or respond to the requirements you wanted there to be :) (bearing in mind i am new to this software) Even I don't understand half the stuff in this post without thinking about it, and I wouldn't consider myself a beginner. |
| ||
| @Dreamora: You're right that my method is not flexible, and the timing can vary a few milliseconds each call. But Robo asked how to call a function, not any potential function, and he did not specify how accurate he needed the timing to be. My way works and is simple, and there is no reason to use a bulldozer to do a shovel's job. If my way suits him, he can use it. If he needs more flexibility, or doesn't like my method for some reason, then he can choose from other methods that have been posted. |
| ||
| Well the type of thing he asked remembers very much of asyncronous function call not "timed repetitive execution" thats why I put mine up. For timed repetitive yours is definitely better. But to have a single time execution at a later time of potentially any function like in his example ([subroutine] means any potential, not a single one over and over again), I assume you agree that it replicates the asked feature more suitable. Both definitely a great technics and should be used together to suite all siutations at with the best approach |