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.
Running the program shows that the counters updated as expected.
In this Racket version:
We use a semaphore instead of a mutex, as Racket doesn’t have a direct equivalent to Go’s sync.Mutex.
The container is implemented as a struct containing a semaphore and a hash table (Racket’s equivalent of Go’s map).
The inc function uses dynamic-wind to ensure the semaphore is properly released, similar to Go’s defer.
We use Racket’s thread function to create concurrent threads, which are similar in concept to goroutines.
Instead of a WaitGroup, we simply collect the threads in a list and use for-each with thread-wait to 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.