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 protected])

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to