Section 7/101 menit

7. Kapan Tidak Digunakan

7. Kapan Tidak Digunakan

Hindari Mutex ketika:

1. Kamu bisa menggunakan actor (async context tersedia)

swift
// JANGAN: menggunakan Mutex jika actor lebih tepat
let stateMutex = Mutex(AppState())
// ... withLock di mana-mana

// LEBIH BAIK: actor untuk async context
actor AppStateManager {
    var state = AppState()
    // ... methods yang jelas isolated
}

2. Operasi di dalam lock sangat lambat (memblokir thread lama)

swift
// JANGAN: melakukan async/network call di dalam withLock
mutex.withLock { _ in
    // ❌ Ini memblokir thread selama lock dipegang
    let data = URLSession.shared.synchronousDataTask(...)  // JANGAN
}

// LEBIH BAIK: ambil state dulu, lalu lakukan operasi di luar lock
let localState = mutex.withLock { $0 }
let data = try await fetchData(using: localState)
mutex.withLock { state in
    state.update(with: data)
}

3. Banyak nested lock yang dibutuhkan

swift
// JANGAN: nested mutex — deadlock risk tinggi
mutex1.withLock { _ in
    mutex2.withLock { _ in  // ⚠️ deadlock potential
        mutex3.withLock { _ in  // ⚠️⚠️ semakin dalam semakin berbahaya
        }
    }
}

// LEBIH BAIK: desain ulang state agar satu mutex cukup

Hindari Atomic ketika:

1. Operasi melibatkan lebih dari satu variabel

swift
// JANGAN: dua atomic yang harus konsisten — bukan atomic bersama!
let balance = Atomic(1000)
let pendingCharges = Atomic(0)

// ❌ Race condition: tidak atomik antar keduanya
let currentBalance = balance.load(ordering: .relaxed)
let pending = pendingCharges.load(ordering: .relaxed)
// Di antara dua load ini, nilai bisa berubah!
let available = currentBalance - pending

// LEBIH BAIK: gunakan Mutex untuk state yang saling terkait
let accountState = Mutex(AccountState(balance: 1000, pendingCharges: 0))

2. Logic kompleks bergantung pada nilai atomic

swift
// JANGAN: check-then-act tanpa atomic — TOCTOU race
let stockCount = Atomic(5)
if stockCount.load(ordering: .acquiring) > 0 {
    // ⚠️ Stock bisa berubah setelah check tapi sebelum decrement!
    stockCount.subtract(1, ordering: .releasing)
}

// LEBIH BAIK: gunakan compareExchange untuk atomic check-and-decrement
var current = stockCount.load(ordering: .relaxed)
while current > 0 {
    let (exchanged, newCurrent) = stockCount.compareExchange(
        expected: current,
        desired: current - 1,
        ordering: .acquiringAndReleasing
    )
    if exchanged { break }  // berhasil decrement
    current = newCurrent    // coba lagi dengan nilai terbaru
}