Reputation: 4386
I have been learning about threading and DispatchQueues a lot recently and have come to a big question. I have heard many times that GCD makes no guarantees about which thread a given block of work may be executed on. Most of the time, this is a helpful level abstraction. However, I'm hitting a bug which I still don't know the cause of, but which caused me to realize what seems to me to be a potential pitfall of this aspect of GCD.
Example:
let queue1 = DispatchQueue(label: "one")
let queue2 = DispatchQueue(label: "two")
queue1.sync {
let importantValue1 = "importantValue1"
let importantValue2 = queue2.sync {
return "importantValue2"
}
print("did important work, got values", importantValue1, importantValue2)
}
My question is, am I at least guaranteed that my queues will not execute on the same thread? From what I've seen it doesn't seem like I have this guarantee. But, without it, am I not in constant jeopardy of deadlock? In the example above, what would happen if both queues execute on Thread 7? Won't the call to queue2.sync
cause the app to crash?
Upvotes: 1
Views: 1465
Reputation: 299275
In most cases, I would expect these two blocks to run on the same queue. In fact, let's see:
import Foundation
let queue1 = DispatchQueue(label: "one")
let queue2 = DispatchQueue(label: "two")
queue1.sync {
let importantValue1 = "importantValue1"
print(Thread.current) // Print the current queue
let importantValue2: String = queue2.sync {
print(Thread.current) // Print the current queue
return "importantValue2"
}
print("did important work, got values", importantValue1, importantValue2)
}
<NSThread: 0x6000023b2900>{number = 1, name = main}
<NSThread: 0x6000023b2900>{number = 1, name = main}
did important work, got values importantValue1 importantValue2
Yeah, in my example both run on the main thread, as you'd generally want them to. There's often no reason to impose the large cost of switching threads when calling .sync
. The current thread can't do anything until the block completes, so it might as well run that block on the current thread as long as there isn't any restriction against that (for example, blocks submitted to the main queue must run on the main thread).
You're correct that it's possible for this to generate deadlocks if you're not careful, but that's not because of the thread that is used. The deadlock would be inherent in using .sync
in a circular way. Whatever underlying thread is used, the queue still has to dispatch blocks in a certain order, and that's what most often creates deadlocks.
Upvotes: 1
Reputation: 52538
Tasks from background queues never prevent other tasks from background queues from running, so while you can get deadlocks, to queues executing on the same thread will not cause it.
On the other hand, running your code synchronous on another queue is rather pointless.
Upvotes: 1