/*:#localized(key: "SerialQueueFix")
 # Fix 1: funnel writes through a serial queue

 The cleanest fix: make the deposits happen **one at a time**. A **serial
 queue** runs its blocks strictly in order, never overlapping, so no teller can
 read the drawer while another is mid-write. There's no gap to slip into.
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

final class Account: @unchecked Sendable {
    var balance = 0
}

let account = Account()

// A serial queue: one block at a time, in order. This is the "single teller
// at the drawer" rule.
let ledger = DispatchQueue(label: "ledger")
let group = DispatchGroup()

for _ in 0..<1_000 {
    ledger.async(group: group) {
        let current = account.balance
        let updated = current + 1
        account.balance = updated
    }
}

group.notify(queue: .main) {
    print("Final balance: \(account.balance) (expected 1000)")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "SerialQueueFix-2")
 **Watch it run:** `Final balance: 1000 (expected 1000)`. Every single time.
 Run it ten times; it's `1000` ten times. The serial queue is the coordination
 the racy version was missing. Note the trade-off: deposits no longer overlap,
 so you've given up some parallelism to buy correctness. For a quick balance
 update that's a fine deal.

 * callout(Try it): Change `ledger` back to `attributes: .concurrent` and run.
 Watch the guaranteed `1000` fall apart again the moment the writes can
 overlap.

 [Previous](@previous)  |  page 4 of 9  |  [Next: The Barrier Fix](@next)
 */
