If I've something that looks like
class Foo {
static shared = Foo()
init() {
print("init Foo")
let _ = Bar.shared
}
}
class Bar {
static shared = Bar()
init() {
print("init Bar")
let _ = Foo.shared
}
}
// somwehere else:
let _ = Foo.shared
then the app gets stuck. Nothing happens. I understand that this design is wrong, but I'm wondering why the app is not crashing, reporting an error or at least printing a loop. The above code print
init Foo
init Bar
and that's it, showing that it is not looping but just getting stuck. An idea on what's happening?
In Swift, static type properties are initialized lazily, in a guaranteed thread-safe manner.
NOTE in Type Properties
Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.
This only once feature utilizes dispatch_once
-like thing (or exactly itself) which needs mutual exclusion.
When initializing Foo.shared
, the lock for Foo.shared
is locked. And while it's locked, Bar.shared
needs to be initialized, so the lock for Bar.shared
is locked. And while both locked, Foo.shared
needs to be initialized, but the lock for it is already locked, so wait there till the lock is freed...
We call this situation a dead-lock.