Tengo el siguiente código de demostración.
struct IdGenerator { private var lastId: Int64 private var set: Set<Int64> = [] init() { self.lastId = 0 } mutating func nextId() -> Int64 { objc_sync_enter(self) defer { objc_sync_exit(self) } repeat { lastId = lastId + 1 } while set.contains(lastId) precondition(lastId > 0) let (inserted, _) = set.insert(lastId) precondition(inserted) return lastId } } var idGenerator = IdGenerator() class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } @IBAction func click(_ sender: Any) { DispatchQueue.global(qos: .userInitiated).async { for i in 1...10000 { let id = idGenerator.nextId() print("i : \(id)") } } DispatchQueue.global(qos: .userInitiated).async { for j in 1...10000 { let id = idGenerator.nextId() print("j : \(id)") } } } } Cada vez que ejecuto click , obtendría el siguiente bloqueo
Thread 5 Queue : com.apple.root.user-initiated-qos (concurrent) #0 0x000000018f58b434 in _NativeSet.insertNew(_:at:isUnique:) () #1 0x000000018f598d10 in Set._Variant.insert(_:) () #2 0x00000001001fe31c in IdGenerator.nextId() at /Users/yccheok/Desktop/xxxx/xxxx/ViewController.swift:30 #3 0x00000001001fed8c in closure #2 in ViewController.click(_:) at /Users/yccheok/Desktop/xxxx/xxxx/ViewController.swift:56 No está claro por qué ocurrió el accidente. Mi conjetura es, bajo struct , objc_sync_enter(self) no funciona como se esperaba. 2 subprocesos que acceden a Set simultáneamente causarán tal problema.
Si cambio la struct a class , todo funciona bien.
class IdGenerator { private var lastId: Int64 private var set: Set<Int64> = [] init() { self.lastId = 0 } func nextId() -> Int64 { objc_sync_enter(self) defer { objc_sync_exit(self) } repeat { lastId = lastId + 1 } while set.contains(lastId) precondition(lastId > 0) let (inserted, _) = set.insert(lastId) precondition(inserted) return lastId } } ¿Puedo saber cuál es la razón detrás? ¿Por qué el objc_sync_enter anterior funciona bien en class , pero no en struct ?