Section 3/101 menit

3. Mutex\<Value\>

3. Mutex<Value>

Konsep Utama: Data dan Lock Tidak Terpisah

Inovasi utama Mutex<Value> adalah bahwa data terkunci langsung di dalam mutex — tidak ada cara untuk mengakses data tanpa lock:

swift
import Synchronization

// Value (Int) dibungkus di dalam Mutex
// Tidak ada cara akses langsung ke Int tanpa withLock
let counter = Mutex(0)

// SATU-SATUNYA cara akses: withLock
counter.withLock { value in
    value += 1
}

// Baca nilai
let current = counter.withLock { $0 }

API Lengkap Mutex

swift
import Synchronization

// Inisialisasi dengan nilai awal
let mutex = Mutex(initialValue)

// withLock: akses eksklusif — parameter adalah inout
mutex.withLock { (value: inout T) in
    // value adalah inout — bisa read dan write
    value = newValue
    let current = value
}

// withLockIfAvailable: non-blocking — returns nil jika lock tidak bisa diperoleh
let result = mutex.withLockIfAvailable { (value: inout T) -> Result in
    // Dieksekusi hanya jika lock tersedia sekarang
    return transform(value)
}
// result adalah Optional — nil jika lock tidak diperoleh

Mutex adalah Sendable

Mutex<Value> adalah Sendable secara otomatis (jika Value-nya Sendable), membuatnya aman untuk digunakan di seluruh isolation domain:

swift
struct AppState: Sendable {
    var user: User?
    var settings: Settings
}

// Mutex bisa dibagikan ke Actor, Task, dll
let sharedState = Mutex(AppState(user: nil, settings: .default))

actor NetworkService {
    let state: Mutex<AppState>  // OK: Mutex adalah Sendable
    
    init(state: Mutex<AppState>) {
        self.state = state
    }
    
    func updateUser(_ user: User) {
        state.withLock { $0.user = user }
    }
}

Nested Mutex — Deadlock Risk

swift
let mutex1 = Mutex(1)
let mutex2 = Mutex(2)

// DEADLOCK RISK: nested withLock
mutex1.withLock { _ in
    mutex2.withLock { _ in  // ⚠️ Bisa deadlock jika thread lain melakukan kebalikannya
        // ...
    }
}

// Solusi: gunakan satu Mutex untuk semua state yang saling terkait
struct CombinedState {
    var value1: Int
    var value2: Int
}
let combined = Mutex(CombinedState(value1: 1, value2: 2))
combined.withLock { state in
    state.value1 += 1
    state.value2 += 2
    // Kedua operasi dalam satu lock — atomic dan tidak deadlock
}