운영체제에서 데드락(교착상태)
란, 시스템의 여러 곳에서 자원을 사용하려고 할 때(다중 처리 환경), 프로세스가 자원을 얻지 못해 다음을 처리하지 못하는 상태(특정 자원을 무한정 기다리는 상태)이다.
let queue = DispatchQueue(label: "label")
queue.async {
queue.sync {
// outer block is waiting for this inner block to complete,
// inner block won't start before outer block finishes
// => deadlock
}
// this will never be reached
}
두 개의 스레드가 하나의 자원을 놓고 서로 사용하려고 경쟁하는 상황. 따라서 데이터 일관성(Data Consistency) 를 해칠 수 있는 상태
해결 방법으로는
iOS앱을 개발하며 Thread를 사용하는 것은 쉽지 않다. 하나의 concurrent queue에서 sync로 막혀있을때, 여러개의 task를 할당할 경우 thread explosion이 발생해 deadlock 상태에 빠지게 된다.
다음과 같은 상황에서는 Thread Explosion 이 일어난다.
// Create Concurrent Queue
let queue = DispatchQueue(label: "com.swiftpal.dispatch.explosion", attributes: .concurrent)
for i in 0 ... 1000 {
// Async Tasks
// 여기서 Thread들이 많이 생성됨
queue.async {
Thread.sleep(forTimeInterval: 1)
print("Executed Task \(i)")
}
}
// Sync Task
// 위의 작업때문에 pool안에 사용할 수 있는 thread가 없음
DispatchQueue.main.sync {
print("All Tasks Completed")
}
따라서 우리는 우리의 task의 갯수를 제한할 필요가 있고, 이런 상황에서 우리는 DispatchSemaphore를 사용한다.
let concurrentTasks = 4
// Create Concurrent Queue
let queue = DispatchQueue(label: "com.swiftpal.dispatch.explosion", attributes: .concurrent)
// Create Semaphore object
let semaphore = DispatchSemaphore(value: concurrentTasks)
for i in 0 ... 100 {
// Async Tasks
queue.async {
Thread.sleep(forTimeInterval: 1)
print("Executed Task \(i)")
semaphore.signal() // Sema Count Increased
}
semaphore.wait() // Sema Count Decreased
}
// Async Task
DispatchQueue.main.async {
print("All Tasks Completed")
}
mutex로 lock을 걸면 락을 건 쓰레드만 임계영역에서 나갈 때 뮤텍스를 해제할 수 있다.
하지만 세마포어는 락을 걸지 않은 쓰레드도 signal을 통해 락을 해제할 수 있다.