study record
[Swift] DispatchSemaphore - Swift에서 세마포어 사용하기! 본문
DispatchSemaphore
class DispatchSemaphore : DispatchObject
디스패치 세마포어는 전통적인 카운팅 세마포어의 효율적인 구현이다. 디스패치 세마포어는 호출 스레드를 차단해야 할 때만 커널을 호출한다. 호출 세마포어가 차단될 필요가 없으면 커널 호출이 이루어지지 않는다.
세마포어 카운트를 증가시키려면 signal() 메서드를 호출하고, 세마포어 카운트를 감소시키려면 wait() 메서드 또는 타임아웃을 지정하는 변형 메서드 중 하나를 호출한다.
세마포어의 정의
정수 변수로서, 멀티프로그래밍 환경에서 공유 자원에 대한 접근을 제한하는 방법으로 사용된다.
스레드가 공유 자원의 배타적인 사용을 보장받기 위해서 임계 구역에 들어가거나 나올때는 세마포어 같은 동기화 매커니즘이 사용된다.
Swift에서의 Semaphore 기능 알아보기!
1. 동시 작업 개수 제한
// 공유 자원에 접근 가능한 작업 수를 2개로 제한
let semaphore = DispatchSemaphore(value: 2)
공유 자원에 접근 가능한 (혹은 한번에 실행 가능한) 작업 수를 명시하고,
임계 구역에 들어갈때는 semaphore의 wait()를, 나올때는 signal()을 호출한다.
for i in 1...3 {
semaphore.wait() //semaphore 감소
DispatchQueue.global().async() { //임계 구역(critical section) print("공유 자원 접근 시작 \(i) ")
sleep(3) print("공유 자원 접근 종료 \(i) ")
semaphore.signal() //semaphore 증가
}
}
wait()는 “나 들어갈테니까 기다려!” 하면서 semaphore를 감소시키고,
signal()은 “나 끝났으니까 신호준다!”하면서 semaphore를 증가시키는 것으로 이해할 수 있다.
이렇게 처음 semephore를 초기화할때 전달한 value (여기서는 2) 안에서 작업의 개수가 왔다갔다 하는 것이다.
공유 자원 접근 시작 1
공유 자원 접근 시작 2
공유 자원 접근 종료 2
공유 자원 접근 종료 1
공유 자원 접근 시작 3
공유 자원 접근 종료 3
3번째 작업이 바로 시작되지 못 하고 1번째 작업이 끝나자 시작되는 것을 볼 수 있다.
동시 작업 개수 2개로 제한!
2. 두 스레드의 특정 이벤트 완료 상태 동기화
DispatchSemaphore는 두 스레드가 특정 이벤트의 완료 상태를 동기화 하는 경우에 유용하다.
- 스레드 A는 작업 A 실행 중
- 스레드 B는 작업 A가 끝난 후에 무언가를 실행하려고함
이 상황에서 스레드 B(소비자)는 예상된 작업을 기다리기 위해 wait를 호출하고,
스레드 A(생성자)는 작업이 준비되면 signal를 호출하는 식으로 스레드 B가 작업 A 의 완료 상태를 동기화할 수 있다는 거죠!!
DispatchSemaphore를 해당 용도로 사용할때는 초기값을 0으로 설정합니다.
//DispatchSemaphore 초기값 0으로 설정
let semaphore = DispatchSemaphore(value: 0)print("task A가 끝나길 기다림")// 다른 스레드에서 task A 실행
DispatchQueue.global(qos: .background).async {
//task A
print("task A 시작!")
print("task A 진행중..")
print("task A 끝!") //task A 끝났다고 알려줌
semaphore.signal()
}// task A 끝날때까지는 value 가 0이라, task A 종료까지 block
semaphore.wait()
print("task A 완료됨")
task A가 끝나지 않았다면 (즉 signal() 이 실행되지 않았다면) semaphore.wait() 이후의 작업은 실행되지 않을 것이다. 왜냐면 그전까지 세마포어 값은 0이기 때문이다.
즉, 두번째 작업을 시작하기 위해서 semaphore 값이 양수여야 하는데 0이어서 첫번째 작업이 끝나서 signal()로 1 값이 되기까지 기다려서 다른 스레드 간의 동기화를 만들 수 있다는 것이다.
마무리
iOS 에서는 Semaphore의 역할을 하는 DispatchSemaphore 가 있고, signal()과 wait() 를 통해 값을 증가/감소 시키면서 특정 영역에 접근 가능한 작업의 수를 제한시킨다.
다른 스레드 간의 동기화 목적으로도 사용가능하다.
참고
- https://developer.apple.com/documentation/dispatch/dispatchsemaphore
- https://sujinnaljin.medium.com/ios-차근차근-시작하는-gcd-10-cb37c3e0cf13
'Swift > 스위프트 정리' 카테고리의 다른 글
[Swift] Struct 내 Class 프로퍼티는 복사될까? isKnownUniquelyReferenced? (0) | 2025.02.01 |
---|---|
[Swift] Creating and Managing Dispatch Queues (0) | 2023.02.13 |
[Swift] Dispatch Queues (0) | 2023.02.07 |
[Swift] Swift 고차함수(map 시리즈, reduce, filter) (0) | 2023.01.30 |
[Swift] Combine 연산자와 CheckedContinuation (0) | 2023.01.29 |