[Swift] DispatchSemaphore

Posted by Kim Heebeom on January 12, 2018

세마포어는 멀티프로그래밍 환경에서 자주 언급되는 중요한 개념이다. 특히 멀티쓰레드에서는 자원의 동기화, 동시성 제어를 위해 꼭 필요하다.

세마포어에서는 P함수V함수 를 가진다. P함수 는 흔히 semWait, V함수semSignal 라고 한다.

Swift에서 제공하는 DispatchSemaphore에서도 동일한 이름의 메소드를 가진다.

let semaphore = DispatchSemaphore(value: 0)
semaphore.wait()
semaphore.signal()

이런식으로 waitsignal 함수를 이용할 수 있다.

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