세마포어

세마포어 (Semaphores)

세마포어는 내부 카운터를 갖고 있어서 스레드 동기화에 사용하는 동시성 도구입니다. 카운터가 0이면 스레드의 실행을 막을 수 있고, 다른 스레드가 카운터를 증가시키면 실행을 재개합니다. 세마포어는 동기화 가능한 이벤트(synchronizable event)로도 사용할 수 있습니다.

출처: Racket Reference

본문

세마포어는 내부 카운터를 갖고 있습니다. 이 카운터가 0이면, 세마포어는 다른 스레드가 카운터를 증가시킬 때까지(semaphore-post 사용) 스레드의 실행을 막을 수 있습니다(semaphore-wait 통해). 세마포어의 내부 카운터 최대값은 플랫폼에 따라 다르지만, 항상 최소 10000은 됩니다.

세마포어의 카운터는 단일 스레드 방식으로 갱신되므로, 세마포어는 신뢰할 수 있는 동기화에 사용될 수 있습니다. 세마포어 대기는 공정(fair)합니다. 스레드가 세마포어에 막혀 있고 세마포어의 내부 값이 무한히 자주 0이 아닐 때, 그 스레드는 결국 풀립니다.

세마포어 특유의 절차들과 함께 쓰는 것 외에도, 세마포어는 동기화 가능한 이벤트(synchronizable event)로 사용할 수 있습니다(Events 참고). 세마포어는 semaphore-wait이 막히지 않을 때 동기화 준비가 되어 있습니다. 동기화가 일어나면 세마포어의 카운터가 감소하고, 세마포어의 동기화 결과는 세마포어 자신입니다.

procedure

(semaphore? v) → boolean?
  v : any/c

v가 세마포어이면 #t를, 그렇지 않으면 #f를 반환합니다.

procedure

(make-semaphore [init]) → semaphore?
  init : exact-nonnegative-integer? = 0

카운터가 처음에 init으로 설정된 새 세마포어를 만들어 반환합니다. init이 세마포어의 최대 내부 카운터 값보다 크면 exn:fail 예외가 발생합니다.

procedure

(semaphore-post sema) → void?
  sema : semaphore?

세마포어의 내부 카운터를 증가시키고 #<void>를 반환합니다. 세마포어의 내부 카운터가 이미 최대값에 도달했다면 exn:fail 예외가 발생합니다.

procedure

(semaphore-wait sema) → void?
  sema : semaphore?

세마포어 sema의 내부 카운터가 0이 아닐 때까지 막습니다. 카운터가 0이 아닐 때는 카운터가 감소되고 semaphore-wait#<void>를 반환합니다.

procedure

(semaphore-try-wait? sema) → boolean?
  sema : semaphore?

semaphore-wait과 비슷하지만, semaphore-try-wait?는 절대 실행을 막지 않습니다. sema의 내부 카운터가 0이면, semaphore-try-wait?는 카운터를 감소시키지 않고 즉시 #f를 반환합니다. sema의 카운터가 양수이면 카운터가 감소되고 #t가 반환됩니다.

procedure

(semaphore-wait/enable-break sema) → void?
  sema : semaphore?

semaphore-wait과 비슷하지만, sema에서 대기하는 동안 브레이크(break)가 활성화됩니다(Breaks 참고). semaphore-wait/enable-break이 호출될 때 브레이크가 비활성화되어 있다면, 세마포어의 카운터가 감소되거나 exn:break 예외가 발생하는데, 둘 다 동시에 일어나지는 않습니다.

procedure

(semaphore-peek-evt sema) → semaphore-peek-evt?
  sema : semaphore?

sync 등과 함께 사용할 수 있는 새 동기화 가능한 이벤트를 만들어 반환합니다. 이 이벤트는 sema가 준비되었을 때 동기화 준비가 되지만, 이벤트를 동기화해도 sema의 내부 카운트는 감소되지 않습니다. 세마포어-피크 이벤트의 동기화 결과는 그 세마포어-피크 이벤트 자신입니다.

procedure

(semaphore-peek-evt? v) → boolean?
  v : any/c

vsemaphore-peek-evt가 만든 세마포어 래퍼(즉 세마포어-피크 이벤트, semaphore wrapper)이면 #t를, 그렇지 않으면 #f를 반환합니다.

procedure

(call-with-semaphore sema
  proc
  [try-fail-thunk]
  arg ...) → any

  sema : semaphore?
  proc : procedure?
  try-fail-thunk : (or/c (-> any) #f) = #f
  arg : any/c

semaphore-wait으로 sema에 대해 대기하고, 모든 arg와 함께 proc을 호출하고, 그 다음 sema에 대해 post합니다. 연속(continuation) 경계(barrier)가 proc 안팎으로의 완전한 연속 점프를 막지만(Prompts, Delimited Continuations, and Barriers 참고), 탈출 점프는 허용되며, 탈출 시 sema는 post됩니다. try-fail-thunk가 제공되고 #f가 아니면, semaphore-wait 대신 semaphore-try-wait?sema에 대해 호출되며, 대기가 실패하면 값 없이 try-fail-thunk가 호출됩니다.

procedure

(call-with-semaphore/enable-break sema
  proc
  [try-fail-thunk]
  arg ...) → any

  sema : semaphore?
  proc : procedure?
  try-fail-thunk : (or/c (-> any) #f) = #f
  arg : any/c

call-with-semaphore과 같지만, 비-시도(non-try) 모드에서 sema에 대해 semaphore-wait/enable-break를 사용한다는 점이 다릅니다. try-fail-thunk가 제공되고 #f가 아니면, sema에 대한 semaphore-try-wait?의 사용 주변에서 브레이크가 활성화됩니다.

더 알아보기

  • 동기화 가능한 이벤트와 sync 관련 문서 (Events, Synchronization)
  • 브레이크(Breaks) 관련 문서
  • 프로세스, 채널, 제너레이터 등 다른 동시성 도구