Le 5 août 2010 à 19:10, Jens Alfke a écrit :
> I’ve got a place in my code where I need to block waiting for an
> otherwise-asynchronous action to complete, so I use a fairly standard
> technique of running a nested runloop. But sometimes the runloop just keeps
> waiting forever even after the action’s completed, so my app locks up.
>
> The wait code looks like:
> while (_busy) {
> if (![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
> beforeDate: [NSDate distantFuture]])
> break;
> }
>
> where _busy is an instance variable that will be set to NO by a notification
> observer method when the async action notifies me that it’s complete.
>
> What I see happening when the bug strikes is that the underlying async code
> completes (it gets a notification from an NSTask it started), but the runloop
> keeps going forever, without returning from my above -runMode: call. This
> doesn’t jibe with my understanding of -runMode: — the docs say it returns
> after an input source is processed.
>
> Here [fig. 1] is the backtrace from gdb at the moment the NSTask notification
> is received. The runloop is inside a function “__CFRunLoopDoBlocks”, which in
> turn calls a block belonging to NSConcreteTask. Presumably this is some
> implementation detail of NSTask, that it uses a block to delay the actual
> launch.
>
> What I’m guessing is that running a delayed block does not count as an “input
> source”. That’s kind of frustrating, because it makes the runloop’s behavior
> highly dependent on internal details of framework classes — in this case, how
> was I to know that NSTask used a block and not an input source to handle
> this? And presumably that means the behavior has changed in 10.6, which would
> explain some weird NSTask related problems I’ve seen over the past year.
> Anyway. How the heck do I work around this? It seems that I need some kind of
> call that will give the runloop a swift kick and get it to exit the runMode:
> method. But I don’t see any explicit API for that.
CFRunLoopWakeUp([[NSRunLoop currentRunLoop ] getCFRunLoop])
and if it is not enough:
CFRunLoopStop([[NSRunLoop currentRunLoop ] getCFRunLoop])
If you want a greater control about how the runloop behave, just use the
CFRunLoop API in your wait loop (especially CFRunLoopRunInMode() which is
roughly equivalent to runMode:beforeDate: but return a status instead of a
boolean).
-- Jean-Daniel
_______________________________________________
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]