동시성 문제는 여러 스레드 또는 동시에 실행되는 코드가 공유된 데이터에 액세스할 때 발생할 수 있습니다. 동시성 문제의 대표적인 예시는 "계좌 이체" 문제입니다.
계좌 이체를 예로 들어 볼 수 있습니다. 두 개의 계좌 A와 B가 있고, A 계좌에서 B 계좌로 일정 금액을 이체하는 상황을 가정해 보겠습니다.
class BankAccount {
private(set) var balance: Int
init(balance: Int) {
self.balance = balance
}
func deposit(_ amount: Int) {
balance += amount
}
func withdraw(_ amount: Int) {
balance -= amount
}
}
func transfer(from accountA: BankAccount, to accountB: BankAccount, amount: Int) {
accountA.withdraw(amount)
accountB.deposit(amount)
}
스레드 A와 스레드 B가 동시에 transfer 함수를 호출하여 서로 다른 계좌에서 동시에 이체를 진행한다고 가정합니다. 이 경우, 동시성 문제가 발생할 수 있습니다.
예를 들어, 스레드 A가 계좌 A에서 금액을 인출한 후, 아직 스레드 B가 계좌 B에 입금하기 전에 스레드 B가 실행되어 계좌 B에서 인출을 진행할 수 있습니다. 이렇게 되면 두 스레드가 동시에 계좌 B에 입금하기 전에 금액을 인출하게 되어 계좌의 잔액이 음수가 될 수 있습니다. 이처럼 동시성 문제는 올바르지 않은 상태가 발생할 수 있습니다.
이 문제를 해결하기 위해 동기화 메커니즘을 사용해야 합니다. Swift의 actor 또는 DispatchSemaphore와 같은 동기화 도구를 사용하여 두 스레드가 동시에 공유된 데이터에 액세스하지 못하게 하여 동시성 문제를 방지할 수 있습니다.
actor BankAccount {
private(set) var balance: Int
init(balance: Int) {
self.balance = balance
}
func deposit(_ amount: Int) {
balance += amount
}
func withdraw(_ amount: Int) {
balance -= amount
}
}
// 이제 transfer 함수를 비동기로 변경하고 actor를 사용합니다.
func transfer(from accountA: BankAccount, to accountB: BankAccount, amount: Int) async {
await accountA.withdraw(amount)
await accountB.deposit(amount)
}
// 사용 예
async {
let accountA = BankAccount(balance: 1000)
let accountB = BankAccount(balance: 500)
// 이제 비동기로 이체 작업을 수행하고, 완료되면 결과를 출력합니다.
await transfer(from: accountA, to: accountB, amount: 200)
print("Account A balance: \(await accountA.balance)")
print("Account B balance: \(await accountB.balance)")
}
위 코드에서 BankAccount 클래스를 actor로 변경했습니다.
이렇게 하면 BankAccount의 내부 상태에 대한 동시 접근이 자동으로 동기화되어 데이터 레이스 조건을 방지합니다.
transfer 함수를 비동기로 변경하고, async/await를 사용하여 계좌 이체 작업을 수행합니다.
이제 transfer 함수에서 await 키워드를 사용하여 actor의 메서드를 호출하면,
메서드 호출이 순차적으로 실행되어 동시성 문제가 발생하지 않습니다.
이렇게 actor와 async/await를 사용하여 동시성 문제를 해결할 수 있습니다.
감사합니다.
'Apple > Apple_Swift' 카테고리의 다른 글
Swift Package Manager(SPM)를 이용해서 라이브러리 만들기 Step By Step (0) | 2024.03.15 |
---|---|
Swift Package Manager(SPM)를 이용한 라이브러리 사용 방법 (2) | 2024.03.14 |
Swift 5.1 Static and class subscripts (SE-0254) (0) | 2023.03.17 |
Swift5.1 불투명 타입 (Opaque type) some Type SE-0244 (0) | 2023.01.20 |
Swift5.1 구조체 멤버별 이니셜라이저(Memberwise Initializer)의 기본값 합성 SE-0242 (0) | 2023.01.16 |