Mutexes in Wolfram Language
In the previous example, we saw how to manage simple counter state using atomic operations. For more complex state, we can use a similar concept to a mutex to safely access data across multiple threads.
(* Container holds an association of counters; since we want to
update it concurrently from multiple threads, we
add a SynchronizedAssociation to synchronize access. *)
container = SynchronizedAssociation[<|"a" -> 0, "b" -> 0|>];
(* This function increments a named counter *)
inc[name_] := container[name] += 1;
(* This function increments a named counter in a loop *)
doIncrement[name_, n_] := Table[inc[name], {n}];
(* Run several ParallelSubmit tasks concurrently; note
that they all access the same container,
and two of them access the same counter. *)
results = ParallelSubmit /@ {
doIncrement["a", 10000],
doIncrement["a", 10000],
doIncrement["b", 10000]
};
(* Wait for all tasks to finish *)
WaitAll[results];
(* Print the final state of the counters *)
Print[Normal[container]]Running the program shows that the counters updated as expected:
<|"a" -> 20000, "b" -> 10000|>In this Wolfram Language version:
We use
SynchronizedAssociationinstead of a custom struct with a mutex. This provides thread-safe access to the counters.The
incfunction is simplified to directly increment the counter in theSynchronizedAssociation.Instead of goroutines, we use
ParallelSubmitto run tasks concurrently. These are similar to threads in other languages.We use
WaitAllto wait for all parallel tasks to complete, which is analogous toWaitGroup.Wait()in the original code.Finally, we use
Normalto convert theSynchronizedAssociationto a regular association for printing.
This implementation achieves the same goal of safely incrementing counters from multiple concurrent tasks, adapting the concepts to Wolfram Language’s built-in concurrency primitives.