Yield in a Cocoa while loop

Oldtimer
Posts: 834
Joined: 2002.09
Post: #1
I'm trying to rework the event handling mechanism in my engine, with the goal of getting it to stop hog 100% CPU when it can. I realize that I should be on a timer, but due to the way its Win port works and the general structure of the engine, this isn't likely to happen anytime now.

I need to enter a function and not return until the application is ready to quit. Right now I do this by trapping myself in a while loop calling

Code:
[[NSRunLoop currentRunLoop] runUntilDate: distantPast];

event = [NSApp    nextEventMatchingMask: eventMask
                untilDate: distantPast
                inMode: NSEventTrackingRunLoopMode
                dequeue: YES];

Unfortunately, this burns through cycles like nothing else since the main thread never yields to other apps. One simple solution would be to add an explicit yield for a fraction of a second after each rendered frame, but I haven't found a way to make Cocoa suspend itself. So, my primary question is if there's a simple, overlooked way to make the run loop run and yield? Would calling runUntilDate: "now + 1/60th second" actually suspend the thread for a while?

Another solution would be to lock myself into a new run loop with a timer that calls my update function at the desired interval - does this sound possible and desirable?

Thanks, as always.
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #2
I'm not sure how well it would work, but one thing to try would be to call usleep with a small interval between event polls. That should at least get your CPU usage under control.
Quote this message in a reply
Member
Posts: 45
Joined: 2006.07
Post: #3
You can also wrap your main loop around a call to select() (on Windows, this is WaitForMultipleObjectsEx or similar). This is essentially what SDL and Qt do under the hood.
Quote this message in a reply
⌘-R in Chief
Posts: 1,256
Joined: 2002.05
Post: #4
If you lock everything to say.... 60fps, you can easily add a bit of timing and a usleep for the extra time.


Code:
while (playing) {
    
    NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
    if (currentTime - _timeOfLastFrame >= 1.0 / _maxNumberOfFramesPerSecond) {
        
        run a frame
    
    } else {
        double timeLeft = ((1.0 / _maxNumberOfFramesPerSecond) - (currentTime - _timeOfLastFrame));
        usleep(1000000 * timeLeft);
    }
}
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
If you're drawing on your main thread, just turn on vsync Wink
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #6
Wow, those are some cool ideas - I have to experiment with them to see what works. Just one question to Keith: I am vsynching, but that only seems to synch the actual page flip to the retrace, not actually block on it? I had hoped for VBL blocking, but since it doesn't seem to take, I started to look for run loop solutions...
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #7
Perhaps you have triple-buffering enabled?
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #8
My bad, I had forgot that I was turning the VBLSync off with a compiler -D define deeper down than where I was looking. Thanks.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Proper game update loop in Cocoa? LoneIgadzra 13 6,637 May 30, 2008 05:49 AM
Last Post: ThemsAllTook
  Cocoa Event Loop/NSTimer revisited Fenris 6 5,278 Oct 29, 2005 11:27 PM
Last Post: maaaaark
  Game Loop in Cocoa robmcq 9 6,205 Sep 27, 2005 10:49 AM
Last Post: akb825