semaphore-utils
call/  sema
8.12

semaphore-utils🔗ℹ

David K. Storrs

 (require semaphore-utils) package: semaphore-utils

A small library for working with semaphores.

procedure

(call/sema sema thnk)  any

  sema : (or/c #f semaphore?)
  thnk : (-> any)
If sema is #f, call thnk with no arguments. If sema is a semaphore?, call thnk with no arguments inside a call-with-semaphore.

This is useful when you two functions that share a semaphore and one of them needs to call the other – it lets you tell the inner one not to use the semaphore since the outer one is already doing so.

; Note: The following code is intended for simplicity of example. In real use it would be
; better to, e.g., not share mutable state between threads and, at a minimum, to expose
; separate versions of the get-* functions that do not allow passing a semaphore in. Also,
; handle the case where a user is not already in the hashes.
; 
> (require racket/splicing semaphore-utils)
> (splicing-let ([sema (make-semaphore 1)]
                 [name->dept-id  (make-hash (list (cons 'alice 1) (cons 'bill 1) (cons 'charlie 2)))]
                 [dept-id->names (make-hash (list (cons 1 (set 'alice 'bob))  (cons 2 (set 'charlie))))])
  
    (define (get-dept-id name [sema sema])
      (call/sema sema (thunk (hash-ref name->dept-id name))))
  
    (define (get-users dept-id [sema sema])
      (call/sema sema (thunk (hash-ref dept-id->names dept-id))))
  
    (define (add-user! name dept-id)
      (call/sema sema
                 (thunk
                  (hash-set! name->dept-id name dept-id)
                  (hash-set! dept-id->names
                             dept-id
                             ; (set-add (get-users dept-id) name))))) ; WRONG! This will deadlock! `sema` is already in use!
                             ; Pass #f as the semaphore so that we don't deadlock
                             (set-add (get-users dept-id #f) name))))))
; 
; If the following functions were running in different threads, the call/sema code would ensure that the 'get-*' functions
; did not interleave with a call to 'add-user!' and thereby see inconsistent state
> (define alice-dept-id (get-dept-id 'alice))
> (get-users alice-dept-id)

#<set: alice bob>

> (add-user! 'evan alice-dept-id)
> (get-users alice-dept-id)

#<set: evan alice bob>