세마포어는 멀티프로그래밍
환경에서 자주 언급되는 중요한 개념이다. 특히 멀티쓰레드에서는 자원의 동기화, 동시성 제어를 위해 꼭 필요하다.
세마포어에서는 P함수 와 V함수 를 가진다. P함수 는 흔히 semWait
, V함수 는 semSignal
라고 한다.
Swift에서 제공하는 DispatchSemaphore에서도 동일한 이름의 메소드를 가진다.
let semaphore = DispatchSemaphore(value: 0)
semaphore.wait()
semaphore.signal()
이런식으로 wait
와 signal
함수를 이용할 수 있다.
let session = URLSession(configuration: .default)
let downloadTask = session.downloadTask(with: url!) { data, response, error in
let data = try? Data(contentsOf: data!)
if let data = data, let image = UIImage(data: data) {
...
}
print("downloadTask'll be terminated")
}
downloadTask.resume()
print("program end")
// print : program end
url로부터 이미지 파일을 다운받는 코드. downloadTask는 다운로드가 완료되면 비동기적으로 클로저를 실행해서 task를 마무리한다.
그렇기 때문에 위와 같이 코드를 짜게되면 다운로드가 끝났다는 "downloadTask'll be terminated"
가 호출되기 전에 "program end"
가 먼저 호출된다.
하지만 원하는 것은 다운로드 작업이 완료되면 프로그램이 종료되는 것이기 때문에, semaphore를 활용해서 동기 방식으로 바꾸자.
let semaphore = DispatchSemaphore(value: 0)
let session = URLSession(configuration: .default)
let downloadTask = session.downloadTask(with: url!) { data, response, error in
let data = try? Data(contentsOf: data!)
if let data = data, let image = UIImage(data: data) {
...
}
print("downloadTask'll be terminated")
semaphore.signal()
}
downloadTask.resume()
semaphore.wait()
print("program end")
// print : downloadTask'll be terminated
// print : program end
딱 3줄 추가.
downloadTask.resume()
을 통해 다운로드를 시작한 후에 semaphore.wait()
를 호출한다.
그렇게 되면, 메인 쓰레드 는 semaphore 자원을 기다리게 되고 누군가 signal
을 호출하여 자원을 사용할 수 있을 때 까지 block
상태가 된다.
[Reference] DispatchSemaphore Reference