8.16.0.1
semaphore-utils
(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>