티스토리 뷰

Swift 이론

DispatchSemaphore 사용하기 (Swift)

Sunghyun Kim 2022. 5. 1. 21:26

https://developer.apple.com/documentation/dispatch/dispatchsemaphore

DispatchSemaphore

전형적인 카운팅 세마포어를 사용하여 여러 실행구문에서 공유하는 리소스에 대한 접근을 제어하는 객체.

세마포어는 한글로 신호기/신호등 정도로 해석이 가능하다.

선언

class DispatchSemaphore : DispatchObject

개요

디스패치 세마포어는 전형적인 카운팅 세마포어의 효율적인 구현이다. 디스패치 세마포어는 실행중인 쓰레드를 블록해야 할 때만 커널을 호출한다. 만약 세마포어가 블록할 필요가 없다면 커널 호출은 발생되지 않는다.

signal() 메소드 호출로 세마포어 카운트를 올리고, wait() 메소드 호출 또는 시간제한 두기를 통해 세마포어 카운트를 내릴 수 있다.

요약

한정된 공유자원에 접근하기 위해 카운팅 세마포어를 사용해 과도한 동시 접근을 막을 수 있다.

활용

wait()는 카운트가 0이면 1 이상이 될 때까지 동기적으로 대기한다. 그리고 대기가 끝나 실행을 하게되면 카운트를 1 줄여 공유자원 접근을 시작했음을 카운팅한다. 그리고 signal()은 카운트를 1 증가시켜 공유자원 접근이 끝남을 카운팅한다.

// 동시에 하나만 접근이 가능한 세마포어를 생성한다.
let semaphore = DispatchSemaphore(value: 1)

DispatchQueue.global().async {
    semaphore.wait()
    print("작업1: 공유자원 접근 시작")
    sleep(1)
    print("작업1: 공유자원 접근 종료")
    semaphore.signal()
}

DispatchQueue.global().async {
    semaphore.wait()
    print("작업2: 공유자원 접근 시작")
    sleep(2)
    print("작업2: 공유자원 접근 종료")
    semaphore.signal()
}

// 출력
//  작업1: 공유자원 접근 시작
//  작업1: 공유자원 접근 종료
//  작업2: 공유자원 접근 시작
//  작업2: 공유자원 접근 종료

//  0s: 작업1 공유자원 접근 시작 및 작업2 대기
//  1s: 작업1 공유자원 접근 종료 후 작업2 공유자원 접근 시작
//  3s: 작업2 공유자원 접근 종료

공유자원 사용이 종료되지 않고 너무 오래지속되는 경우를 대비하여 wait(timeout:)을 통해 시간 제한을 둘 수 있다. 또한 시간제한 내에 완료 여부를 알 수도 있다.

let timeoutResult = semaphore.wait(timeout: .now() + 5)

비동기 함수가 있을 때 동기적으로 실행하게 만들 수도 있다. 세마포어 카운트를 처음부터 0으로 두어 대기하다가 비동기 함수가 종료될 때 signal()을 호출하여 코드 실행을 지속하면 된다.

var file: Data?
let semaphore = DispatchSemaphore(value: 0)

let url = URL(string: "https://example.com/file")!
let task = URLSession.shared.dataTask(with: url) { data, _, _ in
    file = data
    // 비동기 함수가 끝날 때 signal()을 호출
    semaphore.signal()
}

task.resume()
semaphore.wait()
print(file)
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함