커스토디언

커스토디언

커스토디언(custodian)은 스레드, 파일 포트, TCP 소켓 같은 자원들을 한꺼번에 관리하고 정리하는 Racket의 구조체예요. 커스토디언이 종료되면 자신이 관리하는 모든 자원을 일괄적으로 정리해요.

Racket 커스토디언 모델의 기본 정보는 커스토디언 문서를 참고해요.

출처: Racket Reference

본문

procedure

(custodian? v) → boolean?
  • v : any/c

v가 커스토디언 값이면 #t를, 그렇지 않으면 #f를 돌려줘요.

procedure

(make-custodian [cust]) → custodian?
  • cust : (and/c custodian? (not/c custodian-shut-down?)) = (current-custodian)

cust에 종속(subordinate)되는 새 커스토디언을 만들어요. cust가 (즉, custodian-shutdown-all을 통해) 자신이 관리하는 값 전부를 종료하도록 지시받으면, 새로 만든 종속 커스토디언도 자동으로 자신이 관리하는 값들을 종료하도록 지시받아요.

procedure

(custodian-shutdown-all cust) → void?
  • cust : custodian?

racket/gui/base에서, cust가 관리하는 이벤트스페이스(eventspace)도 함께 종료돼요.

cust(및 그 종속 커스토디언들)이 관리하는 모든 파일 스트림 포트, TCP 포트, TCP 리스너, UDP 소켓을 닫고, cust(및 그 종속 커스토디언들)과 연관된 모든 커스토디언 박스(custodian box)를 비워요. 또한 cust(및 그 종속 커스토디언들)을 모든 스레드의 관리자에서 제거하는데, 관리자가 없어진 스레드는 죽거나(thread/suspend-to-kill 참고) 일시중지돼요. 현재 스레드가 죽게 될 경우, 다른 종료 작업이 모두 먼저 수행된 뒤에 스레드가 죽어요.

cust가 이미 종료된 상태라면 custodian-shutdown-all은 아무 효과가 없어요. 커스토디언이 종료될 때 종속 커스토디언이 있다면, 그 종속 커스토디언들도 종료될 뿐만 아니라 더 이상 종속으로 간주되지 않아요.

procedure

(custodian-shut-down? cust) → boolean?
  • cust : custodian?

custcustodian-shutdown-all로 종료되었거나, 종료된 커스토디언의 종속이었다면 #t를, 그렇지 않으면 #f를 돌려줘요.

parameter

(current-custodian) → custodian?
(current-custodian cust) → void?
  • cust : custodian?

커스토디언은 racket/gui/base의 이벤트스페이스도 관리해요.

새로 만들어지는 스레드, 파일 스트림 포트, TCP 포트, TCP 리스너, UDP 소켓, 바이트 변환기의 책임을 지는 커스토디언을 결정하는 파라미터예요.

procedure

(custodian-managed-list cust super) → list?
  • cust : custodian?
  • super : custodian?

cust가 (직접 또는 간접적으로) super에 종속일 때, cust가 즉시 관리하는 객체(커스토디언 박스는 제외)와 종속 커스토디언들의 목록을 돌려줘요. custsuper에 엄격하게 종속이 아니면 exn:fail:contract 예외가 발생해요.

cust가 종료된 상태라면 결과는 '()예요. cust가 종료된 커스토디언의 종속이었다면 super의 종속이 될 수 없어요.

procedure

(custodian-memory-accounting-available?) → boolean?

메모리 회계(accounting)는 보통 사용 가능하지만 CGC 구현에서는 사용할 수 없어요.

Racket이 커스토디언별 메모리 회계를 지원하도록 컴파일되었으면 #t를, 그렇지 않으면 #f를 돌려줘요.

procedure

(custodian-require-memory limit-cust need-amt stop-cust) → void?
  • limit-cust : custodian?
  • need-amt : exact-nonnegative-integer?
  • stop-cust : custodian?

Racket이 커스토디언별 메모리 회계를 지원하도록 컴파일되었으면 필수 메모리 검사(required-memory check)를 등록하고, 그렇지 않으면 exn:fail:unsupported 예외를 발생시켜요.

검사가 등록되고, 가비지 컬렉션(가비지 컬렉션 문서 참고) 이후 Racket이 limit-cust에 부과된 need-amt 바이트를 할당하는 것이 실패하거나 어떤 종료를 유발하는 상태에 도달하면, stop-cust가 종료돼요.

stop-custlimit-cust의 종속 커스토디언이어야 해요.

procedure

(custodian-limit-memory limit-cust limit-amt [stop-cust]) → void?
  • limit-cust : custodian?
  • limit-amt : exact-nonnegative-integer?
  • stop-cust : custodian? = limit-cust

Racket이 커스토디언별 메모리 회계를 지원하도록 컴파일되었으면 제한 메모리 검사(limited-memory check)를 등록하고, 그렇지 않으면 exn:fail:unsupported 예외를 발생시켜요.

검사가 등록되고, 가비지 컬렉션 이후 limit-cust가 소유한 바이트가 limit-amt보다 많아지면 stop-cust가 종료돼요.

커스토디언의 한도는 가비지 컬렉션 이후에만 검사되는데, 단일 할당이 커스토디언 한도보다 커서 개별적으로 검사되는 큰 할당 중에는 검사될 수도 있어요. 한 번의 가비지 컬렉션이 여러 커스토디언을 종료시킬 수 있는데, 그것들이 어느 하나만 종료해도 다른 커스토디언들의 메모리 사용을 줄였을지라도 그래요.

안정적인 종료를 위해, custodian-limit-memorylimit-amt는 사용 가능한 총 메모리(잠재적으로 사용되고 limit-cust에 부과되지 않는 메모리 크기를 뺀 값)보다 훨씬 낮아야 해요. 또한 처음에 limit-cust에 부과되는 개별 할당이 임의로 커질 수 있다면, 지나치게 큰 즉시 할당을 exn:fail:out-of-memory 예외로 거부할 수 있도록 stop-custlimit-cust와 같아야 해요.

새 메모리 할당은 실행 중인 스레드의 관리 커스토디언에 회계된다는 점을 기억해요. 즉, 커스토디언의 한도는 그 커스토디언이 관리하는 스레드가 만든 할당에만 적용돼요. 더 단순한 설정은 call-in-nested-thread도 참고해요.

예시:

> (require racket/async-channel)
> (define ch (make-async-channel))
> (parameterize ([current-custodian (make-custodian)])
    (thread-wait
     (thread
      (λ ()
        (with-handlers ([exn:fail:out-of-memory?
                         (λ (e) (async-channel-put ch e))])
          (custodian-limit-memory (current-custodian) (* 1024 1024))
          (make-bytes (* 4 1024 1024))
          (async-channel-put ch "Not OK")))))
    (async-channel-get ch))
(exn:fail:out-of-memory "out of memory" #<continuation-mark-set>)
> (define cust (make-custodian))
> (with-handlers ([exn:fail:out-of-memory?
                   (λ (e) (error "Caught OOM exn"))])
    (call-in-nested-thread
     (λ ()
       (custodian-limit-memory cust (* 1024 1024))
       (make-bytes (* 4 1024 1024))
       "Not OK")
     cust))
Caught OOM exn

비-예시:

> (parameterize ([current-custodian (make-custodian)])
    (custodian-limit-memory (current-custodian) (* 1024 1024))
    ; make-bytes의 할당은 새 커스토디언이 아니라
    ; 현재 스레드의 관리 커스토디언에 부과된다.
    (make-bytes (* 4 1024 1024))
    "Not OK")
"Not OK"

procedure

(make-custodian-box cust v) → custodian-box?
  • cust : custodian?
  • v : any/c

cust가 종료되지 않는 한 v를 담고 있는 커스토디언 박스를 돌려줘요. cust가 이미 종료된 상태라면 커스토디언 박스의 값은 즉시 제거돼요.

커스토디언 박스는 동기화 가능한 이벤트(이벤트 문서 참고)예요. 커스토디언 박스는 커스토디언이 종료될 때 준비(ready) 상태가 되고, 커스토디언 박스의 동기화 결과는 커스토디언 박스 그 자체예요.

procedure

(custodian-box? v) → boolean?
  • v : any/c

vmake-custodian-box로 만들어진 커스토디언 박스이면 #t를, 그렇지 않으면 #f를 돌려줘요.

procedure

(custodian-box-value cb) → any
  • cb : custodian-box?

주어진 커스토디언 박스의 값을 돌려주거나, 값이 제거되었으면 #f를 돌려줘요.

더 알아보기