How can I run code block in background periodically using GCD? I am trying to write a game engine with several subsystems, like rendering, physics, game logic and so on. Some tasks should be event-driven, but some (like physics system) should be called periodically in the background with constant time (for example after 1/100 sec). I created a block of code, but how can I run this block periodically in background? Is GCD right tool here?
What you want is a GCD dispatch source. For sample code, see the Creating a Timer Example.
As @matt notes in the comments, you can use timer dispatch sources for this. See his answer for the right approach there.
For posterity, here's my original answer with some alternatives:
In your render callback (say, using CADisplayLink), fire off a GCD job that computes the physics for this (or the next?) frame. If you need to do more than one update per render frame, just have that job loop a couple times.
Have a physics thread that sleeps itself until it next needs to do some computation. If you have a separate thread for this, NSTimer might have sufficient resolution to wake your thread up at 100 Hz. (On the main thread, this wouldn't work because other input sources on the runloop will prevent it from firing that fast consistently.) If NSTimer doesn't work, just compute how much time is left until the next physics update you need and sleep your thread (via, e.g., [NSThread sleepForTimeInterval:]
)
Have a block that uses dispatch_after
.
Something like this:
dispatch_time_t next = dispatch_time(DISPATCH_TIME_NOW, 0);
block = ^{
next = dispatch_time(next, 10000000L); // increment by 10 ms
// do physics here
dispatch_after(next, queue, block);
}
You might need to be a bit smarter about dropping frames, (i.e. detect if your next time is in the past before calling dispatch_after it, etc.)
In Swift you can create timer using GCD:
func CreateTimerDispatchSource(interval: UInt64, leeway: UInt64, queue: dispatch_queue_t, block: dispatch_block_t) -> dispatch_source_t {
let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), interval, leeway)
dispatch_source_set_event_handler(timer, block)
return timer;
}
var timer = CreateTimerDispatchSource(5*NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// do some serious stuff
}
Start or resume timer:
dispatch_resume(timer)
Suspend timer:
dispatch_suspend(timer)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With