Mutexes in Racket
In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple threads.
#lang racket
(require racket/hash)
; Container holds a hash of counters; since we want to
; update it concurrently from multiple threads, we
; add a semaphore to synchronize access.
(struct container (semaphore counters))
; Lock the semaphore before accessing `counters`; unlock
; it at the end of the function using dynamic-wind.
(define (inc c name)
(dynamic-wind
(lambda () (semaphore-wait (container-semaphore c)))
(lambda ()
(hash-update! (container-counters c) name add1 0))
(lambda () (semaphore-post (container-semaphore c)))))
(define (main)
(define c (container (make-semaphore 1)
(hash 'a 0 'b 0)))
; This function increments a named counter
; in a loop.
(define (do-increment name n)
(for ([i (in-range n)])
(inc c name)))
; Run several threads concurrently; note
; that they all access the same `container`,
; and two of them access the same counter.
(define threads
(list (thread (lambda () (do-increment 'a 10000)))
(thread (lambda () (do-increment 'a 10000)))
(thread (lambda () (do-increment 'b 10000)))))
; Wait for the threads to finish
(for-each thread-wait threads)
(println (container-counters c)))
(main)Running the program shows that the counters updated as expected.
$ racket mutexes.rkt
'#hash((a . 20000) (b . 10000))In this Racket version:
- We use a
semaphoreinstead of a mutex, as Racket doesn’t have a direct equivalent to Go’ssync.Mutex. - The
containeris implemented as a struct containing a semaphore and a hash table (Racket’s equivalent of Go’s map). - The
incfunction usesdynamic-windto ensure the semaphore is properly released, similar to Go’sdefer. - We use Racket’s
threadfunction to create concurrent threads, which are similar in concept to goroutines. - Instead of a
WaitGroup, we simply collect the threads in a list and usefor-eachwiththread-waitto wait for all threads to complete.
This example demonstrates how to use semaphores in Racket to safely access shared state from multiple threads, achieving the same goal as the original Go program with mutexes.
Next we’ll look at implementing this same state management task using only threads and channels.
Comments powered by Disqus