Middle+
How to solve a race condition problem?
sobes.tech AI
Answer from AI
Use thread synchronization for access to shared resources.
Main approaches:
- Mutexes: Block access to a resource for other threads while one thread is using it.
NSLockos_unfair_lockpthread_mutex_t
import Foundation
let lock = NSLock()
var sharedResource = 0
func modifyResource() {
lock.lock() // Acquire mutex
// Critical section - safe access to sharedResource
sharedResource += 1
print("Resource value: \(sharedResource)")
lock.unlock() // Release mutex
}
// Example calls from different threads
// DispatchQueue.global().async { modifyResource() }
// DispatchQueue.global().async { modifyResource() }
- Serial Queues: Execute tasks one after another, ensuring only one block of code accesses the resource at a time.
DispatchQueue.mainDispatchQueue.global()with.serialattribute
import Foundation
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
var sharedResource = 0
func modifyResourceAsync() {
serialQueue.async {
// Code executes sequentially within this queue
sharedResource += 1
print("Resource value: \(sharedResource)")
}
}
// Example calls from different threads/queues
// modifyResourceAsync()
// modifyResourceAsync()
- Reader-Writer Locks: Allow multiple threads to read a resource simultaneously, but only one thread to write.
DispatchQueuewith barriers (.barrier) for writing and synchronous/asynchronous access for reading.
import Foundation
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
var sharedResource = 0
func readResource() {
concurrentQueue.async { // Reading - multiple readers at once
print("Reading resource: \(sharedResource)")
}
}
func writeResource(newValue: Int) {
concurrentQueue.sync(flags: .barrier) { // Writing - only one writer, no readers/writers
sharedResource = newValue
print("Writing resource: \(sharedResource)")
}
}
// Example calls
// readResource()
// readResource()
// writeResource(newValue: 10)
// readResource()
- Atomic Operations: Operations guaranteed to execute atomically without interruption by other threads. Used for simple data types (counters, flags).
OSAtomicIncrement,OSAtomicDecrement(Deprecated but still relevant)- C++11
<atomic>
#include <atomic>
#include <iostream>
std::atomic<int> atomicCounter(0);
void incrementCounter() {
atomicCounter++; // Atomic increment
std::cout << "Counter: " << atomicCounter << std::endl;
}
// Example in C++ in the context of iOS (using Objective-C++)
// Call from different threads
- Value Types: Passing copies of structs/enums instead of class references can help avoid data races if data is not shared directly between threads in mutable form.
The choice of method depends on the specifics of the task and the required level of parallelism. For most iOS tasks, DispatchQueue (Serial and Concurrent with barriers) is preferred for ease of use and integration with Grand Central Dispatch (GCD).