Middle+
Cum se rezolvă problema condiției de cursă (race condition)?
sobes.tech AI
Răspuns de la AI
Utilizați sincronizarea firelor pentru accesul la resursele partajate.
Abordări principale:
- Mutex-uri (Excludere mutuală): Blochează accesul la o resursă pentru alte fire în timp ce un fir o utilizează.
NSLockos_unfair_lockpthread_mutex_t
import Foundation
let lock = NSLock()
var sharedResource = 0
func modifyResource() {
lock.lock() // Obține mutex-ul
// Secțiunea critică - acces sigur la sharedResource
sharedResource += 1
print("Valoarea resursei: \(sharedResource)")
lock.unlock() // Eliberează mutex-ul
}
// Exemplu de apeluri din fire diferite
// DispatchQueue.global().async { modifyResource() }
// DispatchQueue.global().async { modifyResource() }
- Cozi seriale: Execută sarcinile una după alta, garantând că doar un bloc de cod are acces la resursă în același timp.
DispatchQueue.mainDispatchQueue.global()cu atributul.serial
import Foundation
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
var sharedResource = 0
func modifyResourceAsync() {
serialQueue.async {
// Codul se execută secvențial în această coadă
sharedResource += 1
print("Valoarea resursei: \(sharedResource)")
}
}
// Exemplu de apeluri din fire/queue diferite
// modifyResourceAsync()
// modifyResourceAsync()
- Blochează cititor-writer: Permite mai multor fire să citească resursa simultan, dar doar unuia să scrie.
DispatchQueuecu bariere (.barrier) pentru scris și acces sincron/asynchronous pentru citit.
import Foundation
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
var sharedResource = 0
func readResource() {
concurrentQueue.async { // Citire - mai mulți cititori simultan
print("Citire resursă: \(sharedResource)")
}
}
func writeResource(newValue: Int) {
concurrentQueue.sync(flags: .barrier) { // Scriere - un singur scriitor și nimeni nu citește/scrie
sharedResource = newValue
print("Scriere resursă: \(sharedResource)")
}
}
// Exemplu de apeluri
// readResource()
// readResource()
// writeResource(newValue: 10)
// readResource()
- Operații atomice: Operații garantate pentru a fi executate complet fără întrerupere de către alt fir. Sunt folosite pentru tipuri de date simple (contorizatoare, steaguri).
OSAtomicIncrement,OSAtomicDecrement(Depășit, dar conceptul rămâne relevant)<atomic>în C++11
#include <atomic>
#include <iostream>
std::atomic<int> atomicCounter(0);
void incrementCounter() {
atomicCounter++; // Increment atomic
std::cout << "Contor: " << atomicCounter << std::endl;
}
// Exemplu în context iOS cu C++ (utilizare cu Objective-C++)
// Apelare din fire diferite
- Tipuri de valori: Transmiterea copiilor de structuri/enumerări în loc de referințe la clase poate ajuta la evitarea problemelor de condiții de cursă dacă datele nu sunt partajate direct între fire în mod modificabil.
Alegerea metodei depinde de natura sarcinii și de nivelul de paralelism necesar. Pentru majoritatea sarcinilor în iOS, DispatchQueue (serii și concurente cu bariere) este preferată datorită ușurinței de utilizare și integrării cu Grand Central Dispatch (GCD).