johnbakers
johnbakers

Reputation: 24750

Why does this GCD operation result in deadlock?

I know that deadlock ensues if you call a sync dispatch from another sync dispatch on the same serial queue, but that is the only "known" cause of GCD deadlocks I've heard of.

I am using a global concurrent queue, so I'd expect sync requests to not lead to deadlock. I have this code, which is using ASIHTTPRequest:

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

[self.networkQueue cancelAllOperations];

self.networkQueue=nil;

self.networkQueue=[ASINetworkQueue queue];
});

The idea was to try to speed up the cancelAllOperations part, since that can take quite a long time if you have a couple thousands operations in the networkQueue.

But when I call this code, deadlock ensues. If I take this block out of GCD and run it on the main thread, there is a delay while cancelAllOperations runs, but it does complete without deadlock. When inside this dispatch, however, the app freezes and iOS eventually terminates the app.

Any help is appreciated.

Upvotes: 2

Views: 1622

Answers (1)

jscs
jscs

Reputation: 64002

You have this slightly wrong.

Using dispatch_sync() to enqueue a Block to the serial queue on which you're already running is guaranteed to deadlock.

Using dispatch_sync() to enqueue a Block to the concurrent queue on which you're already running is quite likely to deadlock. You're relying on the queue almost immediately dequeueing the synchronous block, which may or may not happen depending on available resources.

You also seem to be misunderstanding the nature of the concurrency offered by the queue. Submitting [self.networkQueue cancelAllOperations]; to a concurrent queue is not going to speed it up -- that method call isn't sliced into various units of work on the queue. Instead, the entire Block that you've submitted -- all three lines there -- is one unit for the queue. It may run concurrently with other Blocks that you submit, but it cannot itself take advantage of any concurrency. You would have to split the work up yourself and submit each unit as a separate Block -- sending cancel to each operation on the NSOperationQueue, for example.

You should most likely be using dispatch_async() for this.

Upvotes: 1

Related Questions