Re: Run Loop in Tool Idles for 60.0 seconds before exitting
Re: Run Loop in Tool Idles for 60.0 seconds before exitting
- Subject: Re: Run Loop in Tool Idles for 60.0 seconds before exitting
- From: Ken Thomases <email@hidden>
- Date: Sun, 4 Apr 2010 16:44:56 -0500
On Apr 4, 2010, at 4:06 PM, Jerry Krinock wrote:
> while (
> ![[AgentPerformer sharedPerformer] isDone]
> &&
> [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
> beforeDate:[NSDate distantFuture]]) {
> NSLog(@"Did Run") ;
> }
> NSLog(@"Exitting run loop") ;
>
> The work to be done involves about 3 dozen dependent NSOperations, so the "Done Run" logs about 3 dozen times in 10 seconds or so. These operations are also logged. The last operation sets the sharedPerformer's isDone to YES. I expect the run loop to exit immediately, but upon testing *most* builds it sits idle for exactly 60 seconds before "Exitting run loop". Sometimes, seemingly by throwing in extra NSLogs, it exits immediately as expected, but this behavior is not repeatable in any way that I can comprehend.
Have you read and understood the documentation for -[NSRunLoop runMode:beforeDate:]?
Since you specified an infinite timeout, that method blocks until an input source is signaled and handled. As near as I can tell, you are not causing any input source to be signaled. Frankly, it seems like pure luck that it's ever exiting.
If your NSOperations are queued on an operation queue that you allocated, then they will run on background threads, which may not involve the main thread or its run loop, at all. Even if they are queued on the main operation queue (+[NSOperationQueue mainQueue]), it's not clear if that counts as a run loop input source.
> I was wondering if the run loop needed "one last kick", so I added a timer to the last operation. (See code at bottom of post). But that timer never fires, which tells me that the timer's thread is blocked, and this is probably the same thread which is waiting 60 seconds.
If you schedule a timer from an operation that's running on a non-main queue, then that will happen on an arbitrary thread that you don't own and can't make any assumptions about. The timer will be scheduled on that thread's run loop, which is bad.
First, there's no guarantee that the thread will run its run loop, ever.
Second, there's no guarantee that the thread will continue to exist after your -main method exits. It was created automatically, it can be destroyed automatically, too.
Third, even if the timer were to fire, it would not be on the main thread's run loop. Therefore, it would not be expected to affect the main thread's run loop.
Fourth, even if it were to fire on the main thread, the documentation makes it clear that timers don't cause -runMode:beforeDate: to return.
Since you're already using operations, why use the above 'while' loop, anyway? Why not use -[NSOperationQueue waitUntilAllOperationsAreFinished]. Or schedule a "sentinel" operation that depends on all of the other operations, either directly or indirectly, and then invoke -waitUntilFinished on it.
If you prefer, you can keep using your 'while' loop and schedule such a "sentinel" operation on the main queue on the theory that it will count as an input source. While you're at it, that operation's isFinished property would replace the isDone flag.
If that still doesn't work, you can use -performSelector:withObject:afterDelay: (from the main thread) or -performSelectorOnMainThread:withObject:waitUntilDone: (from a background thread) to signal the completion. I believe either of those is known to count as an input source for the purposes of terminating -runMode:beforeDate:.
Regards,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden