iOS 응용 (swift)
[iOS - swift] NSLock과 NSRecursiveLock의 차이 (Critical Section, 멀티 스레드 프로그래밍, thread safe)
jake-kim
2023. 5. 4. 00:14
Critical Section(크리티컬 섹션)
- 한 번에 둘 이상의 스레드가 접근하면 안되는 공유 자원 영역
ex) 멀티 스레드로 처리하는 Data가 있을 때 set이 동시에 이루어지면 안되므로 이 구역을 Critical Section이라고 명칭
NSLock, NSRecursiveLock 개념
- NSLock
- 하나의 스레드 혹은 둘 이상의 스레드가 lock()이 있는 다음 코드 부분을 접근하지 못하도록 상호배제하는 방법
- critical section에 들어갈때 lock()을 걸고 작업을 끝내면 unlock() 호출하는 방법
- NSRecursiveLock
- 둘 이상의 스레드가 lock()이 있는 다음 코드 부분을 접근하지 못하도록 상호배제하는 방법
- NSLock과 NSRecursiveLock 차이
- NSRecursiveLock는 A 스레드가 lock을 걸었을 때, A 스레드가 다시 해당 부분에 접근할 때 lock을 다시 걸을 수 있음
ex) 코드로 NSLock과 NSRecursiveLock 구분하기
- global queue는 concurrent queue이므로 critical section에서 상호배제 처리가 필요하므로 lock 사용
func example1() {
let lock = NSLock()
DispatchQueue.global().async {
lock.lock()
print("Thread 1 is in critical section")
lock.unlock()
}
DispatchQueue.global().async {
lock.lock()
print("Thread 2 is in critical section")
lock.unlock()
}
}
- 같은 스레드가 lock을 통과시키고 싶으면 NSRecursiveLock()을 사용
func example2() {
let recursiveLock = NSRecursiveLock()
func recursiveFunction(count: Int) {
recursiveLock.lock()
if count > 0 {
print("Count is \(count)")
recursiveFunction(count: count - 1)
}
recursiveLock.unlock()
}
recursiveFunction(count: 3)
}
/*
Count is 1
Count is 2
Count is 3
*/
- 만약 위 상황에서 NSLock을 사용하면 영원히 lock 되어있음
func example3() {
let recursiveLock = NSLock()
func recursiveFunction(count: Int) {
recursiveLock.lock()
if count > 0 {
print("Count is \(count)")
recursiveFunction(count: count - 1)
}
recursiveLock.unlock()
}
recursiveFunction(count: 3)
}
/*
Count is 3
... deadlock!
*/
결론
- 같은 스레드에서는 lock을 걸 필요가 없을때는 NSRecursiveLock을 사용할 것
* 전체 코드: https://github.com/JK0369/ExLock
* 참고
https://developer.apple.com/documentation/foundation/nsrecursivelock