En Swift, pour garantir la sécurité des threads, on utilise souvent GCD (Grand Central Dispatch) et les files d'attente (DispatchQueue), NSLock, ainsi que des mécanismes modernes tels que actor (depuis Swift 5.5).
Idée principale – l'accès aux données modifiables se fait soit strictement via des files d'attente séquentielles, soit en utilisant des synchronisateurs (verrous).
Exemple avec GCD :
class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.example.arrayQueue", attributes: .concurrent) func append(_ item: Element) { queue.async(flags: .barrier) { self.array.append(item) } } func get(index: Int) -> Element? { var result: Element? queue.sync { result = self.array.indices.contains(index) ? self.array[index] : nil } return result } }
Approche moderne : Actors (Swift 5.5+) :
actor SafeCounter { private var value = 0 func increment() { value += 1 } func get() -> Int { return value } }
Les deux approches permettent d'éviter les courses de données et de maintenir la cohérence de l'état.
Question :
Si vous utilisez
DispatchQueue.syncdans la Main Queue, que se passera-t-il et pourquoi ?
Réponse : Un blocage intermédiaire (Deadlock) se produira, car la Main Queue exécute déjà une tâche et attend la fin de l'opération synchronisée sur la même file. Par conséquent, la file ne pourra pas traiter la tâche suivante tant que la tâche actuelle n'est pas terminée, ce qui ne se produira jamais.
Exemple :
DispatchQueue.main.sync { // Deadlock : cette ligne ne s'exécutera jamais }
Histoire
Le projet utilisait une collection modifiable, à laquelle plusieurs threads accédaient simultanément sans synchronisation. Cela entraînait des plantages de l'application et des bugs difficilement détectables dus aux courses de données : des éléments étaient parfois perdus, et parfois on sortait des limites du tableau.
Histoire
Un développeur a utilisé de manière incorrecte DispatchQueue.sync sur la file principale en temps d'exécution, ce qui a entraîné un blocage et un arrêt complet de l'interface utilisateur pour les utilisateurs après la sortie de la mise à jour. Un correctif urgent et un retour en arrière du lancement étaient nécessaires.
Histoire
Lorsqu'on a essayé de rendre la classe sûre pour les threads avec NSLock, on a oublié de mettre en œuvre lock/unlock pour tous les chemins de sortie de la méthode (par exemple, en cas d'erreur ou de return à l'intérieur d'un guard), ce qui a entraîné un potentiel de blocages et de problèmes graves de performance de l'application.