Home > Net >  Deadlock in Swift
Deadlock in Swift

Time:04-26

There are two code snippets. 1.

let queue = DispatchQueue(label: "---", qos: .default)
queue.async {
  print("11--\(Thread.current)")
  queue.sync {
    print("22--\(Thread.current)")
  }
}
let queue1 = DispatchQueue(label: "   ", qos: .default)
let queue = DispatchQueue(label: "---", qos: .default)
queue.async {
  print("11--\(Thread.current)")
  queue1.sync {
    print("22--\(Thread.current)")
  }
}

The first one will deadlock, the second one will not deadlock.
In the first code, the result of the two printings is the same thread, so it causes a deadlock; in the second code, the same thread is printed twice, so why not cause a deadlock?

CodePudding user response:

You said:

In the first code, the result of the two printings is the same thread, so it causes a deadlock;

Yes, this code is effectively saying

  1. dispatch this code to the serial queue, running it after everything else on that queue is finished;
  2. because it used sync, it is also telling the current queue to wait and therefore block this serial queue until this dispatched code runs; and
  3. the dispatched code can never run because the queue to which it has been dispatched is blocked.

Deadlock.

Consider:


let queue = DispatchQueue(label: "---")
queue.async {
    print("11--\(Thread.current)")
    queue.sync {
        print("33--\(Thread.current)")   // run after 22, but it can’t because `sync` to same serial queue deadlocks us
    }
    print("22--\(Thread.current)")
}

You continued:

… in the second code, the same thread is printed twice, so why not cause a deadlock?

It’s different because it is saying “block the current serial queue until the code dispatched to a second serial queue finishes”. I.e., the code dispatched to the second queue does not have to wait for all the code dispatched to the first queue to finish. That code running on that second queue only happens to run on the same thread because, as an optimization, GCD is smart enough to determine that it can just run the code on the current thread because that thread is blocked with the sync call anyway. (See notes in the sync documentation.) This GCD optimization just eliminates an unnecessary context switch.

Consider:

let queue1 = DispatchQueue(label: "1")
let queue2 = DispatchQueue(label: "2")
queue1.async {
    print("11--\(Thread.current)")
    queue2.sync {
        print("22--\(Thread.current)")   // run on separate queue after 11 and before 33; no deadlock, even though it may run on same thread as part of GCD optimization
    }
    print("33--\(Thread.current)")
}

CodePudding user response:

A queue is not a thread.

Spawned threads may be (re)used by different queues to execute their scheduled work.
This is what happens in your second example.

The sync function ensure synchronization within the queue.
Not that the piece of code will be executed on a specific tread.
In your example, there's absolutely no reason to execute on a different thread.

The deadlock in the first example comes from the fact you are executing synchronously on the currently running queue.
It's not related to threads.
It doesn't happen on the second because the queues are different (eg a different mutex is used for synchronization), even if the same thread is used.

  • Related