Middle+
Hoe los je het probleem van raceconditie op?
sobes.tech AI
Antwoord van AI
Gebruik thread-synchronisatie voor toegang tot gedeelde bronnen.
Belangrijkste benaderingen:
- Mutexen (Mutual Exclusion): Blokkeert toegang tot een bron voor andere threads terwijl één deze gebruikt.
NSLockos_unfair_lockpthread_mutex_t
import Foundation
let lock = NSLock()
var sharedResource = 0
func modifyResource() {
lock.lock() // Mutex verkrijgen
// Kritieke sectie - veilige toegang tot sharedResource
sharedResource += 1
print("Resourcewaarde: \(sharedResource)")
lock.unlock() // Mutex vrijgeven
}
// Voorbeeld van aanroepen vanuit verschillende threads
// DispatchQueue.global().async { modifyResource() }
// DispatchQueue.global().async { modifyResource() }
- Seriële wachtrijen: Voeren taken één voor één uit, waardoor gegarandeerd wordt dat slechts één codeblok toegang heeft tot de bron tegelijk.
DispatchQueue.mainDispatchQueue.global()met.serialattribuut
import Foundation
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
var sharedResource = 0
func modifyResourceAsync() {
serialQueue.async {
// Code wordt sequentieel uitgevoerd in deze wachtrij
sharedResource += 1
print("Resourcewaarde: \(sharedResource)")
}
}
// Voorbeeld van aanroepen vanuit verschillende threads/wachtrijen
// modifyResourceAsync()
// modifyResourceAsync()
- Lezer-schrijf vergrendelingen: Mogen meerdere threads tegelijk lezen, maar slechts één schrijven.
DispatchQueuemet.barrierbarrières voor schrijven en synchronisatie/asynchrone toegang voor lezen.
import Foundation
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
var sharedResource = 0
func readResource() {
concurrentQueue.async { // Lezen - meerdere lezers tegelijk
print("Lezen van resource: \(sharedResource)")
}
}
func writeResource(newValue: Int) {
concurrentQueue.sync(flags: .barrier) { // Schrijven - slechts één schrijver en niemand leest/schrijft
sharedResource = newValue
print("Schrijven naar resource: \(sharedResource)")
}
}
// Voorbeeld van aanroepen
// readResource()
// readResource()
// writeResource(newValue: 10)
// readResource()
- Atomische operaties: Operaties die gegarandeerd volledig worden uitgevoerd zonder onderbreking door andere threads. Gebruikt voor eenvoudige datatypes (telers, flags).
OSAtomicIncrement,OSAtomicDecrement(Verouderd, maar concept blijft relevant)<atomic>in C++11
#include <atomic>
#include <iostream>
std::atomic<int> atomicCounter(0);
void incrementCounter() {
atomicCounter++; // Atomische increment
std::cout << "Counter: " << atomicCounter << std::endl;
}
// Voorbeeld in iOS-context met C++ (gebruik met Objective-C++)
// Aanroepen vanuit verschillende threads
- Value types: Het doorgeven van kopieën van structuren/enums in plaats van referenties naar klassen kan helpen om racecondities te voorkomen, als de gegevens niet direct tussen threads worden gedeeld in wijzigbare vorm.
De keuze van methode hangt af van de aard van de taak en het vereiste niveau van parallelisme. Voor de meeste taken in iOS zijn DispatchQueue (serieel en gelijktijdig met barrières) de voorkeur vanwege gebruiksgemak en integratie met Grand Central Dispatch (GCD).