Re: My runloop-based async code breaks with GCD
Re: My runloop-based async code breaks with GCD
- Subject: Re: My runloop-based async code breaks with GCD
- From: Ken Thomases <email@hidden>
- Date: Fri, 17 Feb 2012 23:34:04 -0600
On Feb 17, 2012, at 6:22 PM, Jens Alfke wrote:
> The trouble I’m having is that neither GCD dispatch_queues nor NSOperationQueues seem to have runloops, so any code that explicitly or implicitly uses runloops for scheduling breaks when it’s invoked from a block running on a dispatch or operation queue.
All threads have run loops. The question is, is it devoting time to running that run loop. Other than the main event loop, run loops are not run for you. You have to invoke a method or function which is directly about running the run loop or is documented to run the run loop (for example, -[NSTask waitUntilExit]).
Neither GCD nor NSOperationQueue changes anything in this regard. The same is true if you use NSThreads or -performSelectorInBackground:withObject:.
> • NSURLConnection doesn’t ever call its delegate methods, unless you call its -setDelegateQueue: method. (Which requires an NSOperationQueue, so it only works if you’re using those, not if you use dispatch queues directly.)
> • -[NSObject performSelector:withObject:afterDelay:] doesn’t work. No exceptions, but it never performs the selector. I haven’t figured out a workaround for this yet.
Correct. These are well known cases. There's nothing surprising here. They both entail scheduling a runloop source on the current runloop. If the runloop is never run, though, those sources can never fire.
> What concerns me the most is that it seems like there are now at least three different incompatible operating environments for working with asynchronous operations: a normal thread with a runloop, an NSOperation, and a block invoked directly from a dispatch queue.
Nope, they work the same way.
> If you want to schedule a call after a delay, or a delegate callback that should be invoked later, the code doing so has to figure out somehow what mode it’s in and make different API calls accordingly.
Nope. You have to run the run loop.
> That’s going to complicate code that wants to be reusable, and it means that code I’ve written over the past decade in the normal runloop environment is going to break in subtle and hard-to-debug ways with GCD unless I fix it to handle all of these situations.
The code you've written doesn't depend on "the normal runloop environment". It depends on the main event loop automatically running the run loop for you. You've written main-thread-only code. You can't expect to convert it to multi-threaded code without some redesign work.
In some cases, that will entail running a run loop on a background thread. However, if you can avoid blocking a thread, including having it sit in a runloop-running method waiting for something to process, that would be better.
In some cases, you should leave the stuff on the main thread because it's already asynchronous and can be handled just fine there.
In some cases, you should move away from runloop-dependent API, such as -performSelector:withObject:afterDelay:, and just submit operations to operations queues or tasks to dispatch queues. Or use timer dispatch sources.
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