Atomic Counters in Racket

Here’s the translation of the atomic counter example from Go to Racket:

Our primary mechanism for managing state in Racket is through mutable variables and data structures. In this example, we’ll look at using Racket’s built-in atomic operations for creating an atomic counter accessed by multiple threads.

#lang racket

(require racket/place)

(define (main)
  ; We'll use an atomic box to represent our (always-positive) counter.
  (define ops (box 0))

  ; We'll start 50 threads that each increment the counter exactly 1000 times.
  (define threads
    (for/list ([i (in-range 50)])
      (thread
       (λ ()
         (for ([c (in-range 1000)])
           ; To atomically increment the counter we use atomic-set!.
           (atomic-set! ops (add1 (unbox ops))))))))

  ; Wait until all the threads are done.
  (for-each thread-wait threads)

  ; Here no threads are writing to 'ops', but it's safe to read the value.
  (printf "ops: ~a\n" (unbox ops)))

(main)

In this Racket version:

  1. We use (box 0) to create a mutable box that will serve as our atomic counter.

  2. Instead of goroutines, we use Racket’s built-in thread function to create 50 separate threads.

  3. The atomic-set! function is used to atomically update the counter. It ensures that the read-modify-write operation is atomic.

  4. We use thread-wait to wait for all threads to complete, similar to the WaitGroup in the Go version.

  5. Finally, we can safely read the value of the counter using unbox.

To run this program, save it as atomic-counters.rkt and use the Racket interpreter:

$ racket atomic-counters.rkt
ops: 50000

We expect to get exactly 50,000 operations. If we had used a non-atomic operation like (set-box! ops (add1 (unbox ops))), we might get a different number, changing between runs, because the threads would interfere with each other.

Note that Racket’s threading model is different from Go’s, and the performance characteristics may vary. However, this example demonstrates how to achieve similar atomic counter behavior in Racket.