본문 바로가기
ios/swift

Dispatch Semaphore

by kimyounggyun 2022. 9. 1.

세마포어(Semaphore)

비동기 처리로 인해 공유 자원에 동시에 접근하여 데이터 불일치가 발생하는 경쟁 상태를 막기 위해 스레드(혹은 프로세스) 간의 동기화가 필요하다. 임계 구역(Critical Section)에 한 개의 스레드가 접근했다면 다른 스레드에서는 접근하지 못하도록 해야 한다. 세마포어(Semaphore)는 임계 구역 문제(Critical Section Problem)를 해결하기 위한 여러 가지 방법 중 한 개다.

 

세마포어는 양수 값\((S)\)으로 \(S\)를 수정하는 두 가지 연산을 수행한다.

  • wait : 만약 값이 0이 아니면 하나 감소시키고 critical section에 진입한다. 그렇지 않으면 signal 연산이 실행되어 값이 증가하기 전까지 해당 작업을 차단한다. 
  • signal :  값을 증가시키고 대기 중인 스레드가 있는 경우 스레드의 차단을 해제한다.

디스패치 세마포어(Dispatach Semaphore)

An object that controls access to a resource across multiple execution contexts through use of a traditional counting semaphore. 

IOS의 디스패치 세마포어(Dispatch Semaphore)는 계수 세마포어(Counting Semaphore)로 초기 값으로 접근 가능한 스레드의 개수를 갖는다. 디스패치 세마포어는 최대 N개의 스레드에서 동시에  접근할 수 있는 자원이 있을 때 사용할 수 있다. 세마포어의 초기 값을 N으로 설정하면 처음 N개의 스레드는 차단되지 않고 동시에 자원에 접근할 수 있지만 N+1번째 스레드부터는 이전 N개의 스레드에서 signal 메서드가 실행되어 세마포어의 값이 양수가 될 때까지 차단된다. N = 1로 설정하면 뮤텍스 락(mutex lock) 기능을 할 수 있다.

init(value: Int) // Creates new counting semaphore with an initial value.
let semaphore = DispatchSemaphore(value: 3)

세마포어의 값을 3으로 설정하고 5개의 작업을 큐로 보낼 때 5개 작업이 모두 스레드에 배정되는 것이 아닌 3개의 작업만 스레드에 배정된다. 4번째 작업의 wait()를 실행하고 작업을 큐에 넣었을 때 이미 세마포어의 값은 0이기 때문에 4번째 작업은 차단된다.

task1이 끝나고 signal()를 실행해 세마포어의 값을 1로 올리면 task4의 차단이 해제되고 task4의 작업이 시작된다.

디스패치 그룹과 사용

디스패치 세마포어는 디스패치 그룹과 같이 사용할 수 있다. 작업을 하나의 그룹으로 묶고 세마포어를 통해 최대 실행될 작업의 개수를 제한해 마지막 작업이 끝났을 때 notify하게 할 수도 있다.

댓글