이번엔 두번째로 Deadlock 에 대해서 알아보자
Deadlock?
먼저 데드락이란 여러 스레드가 서로가 가진 리소스를 기다리면서 계속 실행이 중단되어있는 상태를 말한다. iOS 개발에서는 멀티스레드 환경에서 동기 작업을 수행하거나 서로 잠긴 리소스를 접근할 때 발생하곤 한다.
Deadlock 예시
예시를 통해서 살펴보자
- DispatchQueue 데드락
import Foundation
func deadlockExample() {
let queue = DispatchQueue(label: "com.example.queue")
queue.sync {
print("Task started")
queue.sync {
// 여기서 데드락 발생
print("Inner task started")
}
print("Task finished")
}
}
queue.sync 를 호출하면 현재 실행중인 스레드에서 해당 작업이 완료될 때까지 기다린다. 그 이후 내부에서 같은 queue에 sync 작업을 호출하면 외부 작업이 끝나기를 기다리지만, 외부 작업은 내부작업의 완료를 기다리고 있는 상태가 되어 데드락이 발생하는 상태이다!
- NSLock을 통한 데드락
두 개의 스레드가 서로 다른 리소스를 잠그고, 서로의 리소스를 기다릴때 데드락이 발생할 수 있다. 코드를 통해 살펴보면
import Foundation
let lock1 = NSLock()
let lock2 = NSLock()
func thread1() {
lock1.lock()
print("Thread 1: lock1 acquired")
sleep(1) // Simulate some work
lock2.lock()
print("Thread 1: lock2 acquired")
lock2.unlock()
lock1.unlock()
}
func thread2() {
lock2.lock()
print("Thread 2: lock2 acquired")
sleep(1) // Simulate some work
lock1.lock()
print("Thread 2: lock1 acquired")
lock1.unlock()
lock2.unlock()
}
let queue = DispatchQueue.global()
queue.async {
thread1()
}
queue.async {
thread2()
}
첫번째 스레드는 lock1을 얻고, lock2를 기다린다. 두번째 스레드는 lock2를 얻고 lock1을 기다린다. 서로가 서로의 리소스를 기다리므로 데드락이 발생하는 상황!!
이렇게 데드락이 발생하는 상황에 대해서 예시를 통해 알아보았으니 이제 데드락을 방지하는 방법에 대해서도 알아보자!
데드락 방지 방법
- 동기 작업 사용 최소화
가능하면 비동기 작업을 사용해 데드락 발생 가능성을 줄이자!
queue.async {
print("Task executed asynchronously")
}
- 계층적 잠금 순서
여러 리소스를 잠글 때 항상 일정한 순서로 잠금을 적용한다!!
func thread1() {
lock1.lock()
lock2.lock()
// 작업 수행
lock2.unlock()
lock1.unlock()
}
- 재귀적 잠금 사용
같은 스레드가 여러번 잠금 호출을 해야 할 경우 NSRecursiveLock을 사용한다.
let recursiveLock = NSRecursiveLock()
func recursiveFunction(_ n: Int) {
recursiveLock.lock()
if n > 0 {
print("Recursing \\(n)")
recursiveFunction(n - 1)
}
recursiveLock.unlock()
}
DispatchQueue.global().async {
recursiveFunction(5)
}
NSRecursiveLock 은 재귀적 잠금을 제공하는 객체인데 기본적으로 잠금은 동일한 스레드가 동일한 잠금 객체를 여러번 잠그려고 할 때 데드락이 발생할 수 있기 때문에 NSRecursiveLock는 동일한 스레드가 이미 잠긴 상태에서 다시 잠금을 시도하는 것을 허용한다.
동일한 스레드에서 여러번 lock()을 호출 할 수 있고 동일한 스레드에서 호출된 lock() 마다 반드시 동일한 수의 unlock()을 호출해야 잠금이 해제된다.
이것으로 데드록에 대해서 한번 알아봤는데 예제를 통해 보니 어느정도 어떻게 생기는 문제인지 인식은 되는 것 같다 ㅎㅎ GCD에 대해서 자세하게 공부를 다시하면서 엘런강의가 잘나온게 있어서 땡기는데.. 결제해서 들어봐야겠다
'◽️ Programming > iOS' 카테고리의 다른 글
JWT의 기본 개념과 HaruFit 프로젝트에 적용해보기 (0) | 2025.01.12 |
---|---|
Swift Format , Swift Lint 프로젝트에 적용하기 (0) | 2025.01.07 |
멀티 쓰레드 환경에서 Race Condition에 대해서 알아보자 (0) | 2024.12.09 |
WKWebView를 사용해 웹페이지 가져오기 (1) | 2024.12.02 |
@AppStorage , UserDefaults의 특징 (0) | 2024.10.18 |