Mutexes in PureScript
In the previous example, we saw how to manage simple counter state using atomic operations. For more complex state, we can use a Ref
to safely access data across multiple fibers.
module Main where
import Prelude
import Effect (Effect)
import Effect.Console (log)
import Effect.Ref as Ref
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Control.Parallel (parallel, sequential)
We’ll create a Container
type that holds a map of counters. Since we want to update it concurrently from multiple fibers, we’ll use a Ref
to synchronize access.
type Container = Ref.Ref (Map.Map String Int)
-- Increment the counter for a given name
inc :: Container -> String -> Effect Unit
inc container name = Ref.modify_ (Map.alter increment name) container
where
increment Nothing = Just 1
increment (Just n) = Just (n + 1)
The inc
function uses Ref.modify_
to safely update the counter. This ensures that updates are atomic and thread-safe.
main :: Effect Unit
main = do
-- Create a new container with initial counters
c <- Ref.new $ Map.fromFoldable [Tuple "a" 0, Tuple "b" 0]
-- This function increments a named counter in a loop
let doIncrement name n =
sequence_ $ replicate n (inc c name)
-- Run several fibers concurrently
_ <- sequential $ parallel (doIncrement "a" 10000)
*> parallel (doIncrement "a" 10000)
*> parallel (doIncrement "b" 10000)
-- Print the final state of the counters
result <- Ref.read c
log $ show result
In the main
function, we create a new Container
and define a doIncrement
function that increments a named counter multiple times. We then run three fibers concurrently using parallel
, two of which access the same counter.
Running the program shows that the counters are updated as expected:
$ spago run
Map (fromFoldable [Tuple "a" 20000,Tuple "b" 10000])
This example demonstrates how to use Ref
in PureScript to manage shared state across multiple fibers. While PureScript doesn’t have built-in mutexes like some other languages, the Ref
type provides a safe way to handle concurrent access to mutable state.
Next, we’ll look at implementing this same state management task using only fibers and channels.