Mutexes in ActionScript

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.

package {
    import flash.utils.Dictionary;
    import flash.events.EventDispatcher;
    import flash.events.Event;

    public class MutexExample extends EventDispatcher {
        private var mutex:Object = new Object();
        private var counters:Dictionary = new Dictionary();

        public function MutexExample() {
            counters["a"] = 0;
            counters["b"] = 0;
        }

        private function inc(name:String):void {
            synchronized(mutex) {
                counters[name]++;
            }
        }

        public function runExample():void {
            var totalThreads:int = 3;
            var completedThreads:int = 0;

            var doIncrement:Function = function(name:String, n:int):void {
                for (var i:int = 0; i < n; i++) {
                    inc(name);
                }
                completedThreads++;
                if (completedThreads == totalThreads) {
                    dispatchEvent(new Event(Event.COMPLETE));
                }
            };

            for (var i:int = 0; i < 2; i++) {
                setTimeout(doIncrement, 0, "a", 10000);
            }
            setTimeout(doIncrement, 0, "b", 10000);

            addEventListener(Event.COMPLETE, function(e:Event):void {
                trace(counters);
            });
        }
    }
}

In this ActionScript implementation, we create a MutexExample class that holds a dictionary of counters. Since we want to update it concurrently from multiple threads, we use the synchronized keyword to ensure thread-safe access.

The inc function increments a named counter in the dictionary. It uses the synchronized keyword to lock the mutex before accessing the counters, ensuring that only one thread can modify the counters at a time.

In the runExample function, we define a closure doIncrement that increments a named counter in a loop. We then use setTimeout to schedule these increments to run asynchronously, simulating concurrent execution.

We use an EventDispatcher to signal when all threads have completed their work. When the last thread finishes, it dispatches a COMPLETE event, which triggers the final output of the counters.

To run the example:

var example:MutexExample = new MutexExample();
example.runExample();

This will output the final state of the counters, which should show that “a” was incremented 20000 times and “b” was incremented 10000 times.

Note that ActionScript doesn’t have built-in support for true multithreading. This example uses asynchronous operations to simulate concurrent execution, but it’s not a perfect analogy to the original Go example with goroutines.