Middle+
Kako rešiti problem trka (race condition)?
sobes.tech АИ
Одговор од АИ
Korišćenje sinhronizacije niti za pristup zajedničkim resursima.
Glavni pristupi:
- Muteksi (Zaključavanje): Blokiraju pristup resursu drugim nitima dok jedna nit koristi resurs.
NSLockos_unfair_lockpthread_mutex_t
import Foundation
let lock = NSLock()
var sharedResource = 0
func modifyResource() {
lock.lock() // Zauzimanje muteksa
// Kritična sekcija - siguran pristup sharedResource
sharedResource += 1
print("Vrednost resursa: \(sharedResource)")
lock.unlock() // Oslobađanje muteksa
}
// Primer poziva iz različitih niti
// DispatchQueue.global().async { modifyResource() }
// DispatchQueue.global().async { modifyResource() }
- Serijska reda (Serial Queues): Izvršavaju zadatke jedan za drugim, garantujući da samo jedan blok koda istovremeno ima pristup resursu.
DispatchQueue.mainDispatchQueue.global()sa atributom.serial
import Foundation
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
var sharedResource = 0
func modifyResourceAsync() {
serialQueue.async {
// Kod se izvršava sekvencijalno
sharedResource += 1
print("Vrednost resursa: \(sharedResource)")
}
}
// Primer poziva iz različitih niti/redova
// modifyResourceAsync()
// modifyResourceAsync()
- Čitaoci-Pisci (Reader-Writer) Lockovi: Omogućavaju više čitaoca da čitaju istovremeno, ali samo jedan piše.
DispatchQueuesa barijerama (.barrier) za zapis i sinhronim/asinkronim pristupom za čitanje.
import Foundation
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
var sharedResource = 0
func readResource() {
concurrentQueue.async { // Čitanje - više čitalaca istovremeno
print("Čitanje resursa: \(sharedResource)")
}
}
func writeResource(newValue: Int) {
concurrentQueue.sync(flags: .barrier) { // Zapis - samo jedan pisac i niko ne čita/ne piše
sharedResource = newValue
print("Pisanje u resurs: \(sharedResource)")
}
}
// Primer poziva
// readResource()
// readResource()
// writeResource(newValue: 10)
// readResource()
- Atomične operacije: Operacije koje se garantovano izvršavaju celovito bez prekida od strane drugog toka. Koriste se za jednostavne tipove podataka (brojači, zastavice).
OSAtomicIncrement,OSAtomicDecrement(zastarelo, ali koncept je i dalje relevantan)- C++11
<atomic>
#include <atomic>
#include <iostream>
std::atomic<int> atomicCounter(0);
void incrementCounter() {
atomicCounter++; // Atomsko inkrementiranje
std::cout << "Brojač: " << atomicCounter << std::endl;
}
// Primer C++ u kontekstu iOS (korišćenje sa Objective-C++)
// Pozvati iz različitih niti
- Tipovi vrednosti: Prenos kopija struktura ili enumeracija može pomoći u izbegavanju problema sa race condition ako podaci nisu direktno deljeni između niti u promenljivom obliku.
Izbor metode zavisi od specifičnosti zadatka i nivoa paralelizma koji je potreban. Za većinu zadataka u iOS, preporučuju se DispatchQueue (serijski i paralelni sa barijerama) zbog jednostavnosti korišćenja i integracije sa Grand Central Dispatch (GCD).