Atomic Counters in F#
Our primary mechanism for managing state in F# is typically through immutable data structures and functional programming patterns. However, there are scenarios where we need to manage shared mutable state across multiple threads. In this example, we’ll look at using atomic operations for managing a counter accessed by multiple threads.
In this F# version:
We use
ref
to create a mutable reference cell for our counter, initialized to 0L (long integer).Instead of goroutines, we use F#’s
Task.Run
to create and run tasks concurrently.We use
Interlocked.Increment
for atomic incrementation of the counter. This is equivalent to theAdd
method used in the original example.We use
Task.WaitAll
to wait for all tasks to complete, which is similar to theWaitGroup.Wait()
in the original.After all tasks are complete, we can safely read the value of
ops
using the!
operator to dereference the ref cell.
When you run this program, you should see:
We expect to get exactly 50,000 operations. If we had used a non-atomic integer and incremented it with normal addition, we’d likely get a different number, changing between runs, because the tasks would interfere with each other.
This example demonstrates how to use atomic operations in F# for safe concurrent access to shared mutable state. However, in idiomatic F# programming, you would typically prefer immutable data structures and message-passing concurrency models when possible.