The Condition class that debuted alongside the Mutex class in Flash Player 11.5 is very useful but much less understood. Unfortunately, Adobe’s documentation doesn’t include a usage example and there seem to be none available elsewhere on the internet. So today’s article provides an example of how to use the flash.concurrent.Condition class.

The Condition class contains a Mutex which it uses to control a “resource”, just like the plain usage of Mutex. However, it adds functionality to Mutex such as the ability to notify multiple workers that you’re done with the resource without any one of them needing to take exclusive control of the Mutex. This can simplify coordination between workers and help you avoid subtle bugs.

The following example shows a very simple usage of the Condition class. The main thread/worker creates a ByteArray and uses a worker thread to compress it. You might do this in order to maintain UI responsiveness on the main thread while compressing some data for upload to a server, for example. A Condition is used to control access to the shared ByteArray resource. The code is thoroughly documented and minimal, so hopefully you’ll be able to follow the flow of control between the two workers.

package
{
	import flash.concurrent.Mutex;
	import flash.concurrent.Condition;
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.system.Worker;
	import flash.system.WorkerDomain;
	import flash.utils.ByteArray;
 
	/**
	* Test to show the usage of the Condition class
	* @author Jackson Dunstan (JacksonDunstan.com)
	*/
	public class ConditionTest extends Sprite
	{
		/**
		* Start the app in main thread or worker thread mode
		*/
		public function ConditionTest()
		{
			// If this is the main SWF, start the main thread
			if (Worker.current.isPrimordial)
			{
				startMainThread();
			}
			// If this is the worker thread SWF, start the worker thread
			else
			{
				startWorkerThread();
			}
		}
 
		/**
		* Start the main thread
		*/
		private function startMainThread(): void
		{
			// Create a Condition that we'll wait on until the worker thread is
			// done with its work of compressing our ByteArray. The Condition's
			// mutex is initially locked so we can unlock it only when we're
			// ready for the worker to start compressing.
			var conditionMutex:Mutex = new Mutex();
			conditionMutex.lock();
			var condition:Condition = new Condition(conditionMutex);
 
			// Create a 32 megabyte ByteArray for the worker to compress
			const SIZE:uint = 1024*1024*32;
			var bytes:ByteArray = new ByteArray();
			bytes.length = SIZE;
			bytes.shareable = true;
 
			// Create the worker from our own SWF bytes
			var swfBytes:ByteArray = this.loaderInfo.bytes;
			var worker:Worker = WorkerDomain.current.createWorker(swfBytes);
 
			// Share the bytes and condition with the worker
			worker.setSharedProperty("bytes", bytes);
			worker.setSharedProperty("condition", condition);
 
			// Start the worker
			worker.start();
 
			// Unlock the Condition's mutex and suspend the main thread until
			// the worker thread is done compressing the ByteArray. At that
			// point it will call notify() on the Condition which will resume
			// this thread right after its call to wait().
			condition.wait();
 
			// Output some statistics about the work that was done
			var logger:TextField = new TextField();
			logger.autoSize = TextFieldAutoSize.LEFT;
			logger.text = SIZE + " bytes compressed to " + bytes.length
				+ " bytes (" + ((bytes.length*100.0)/SIZE).toFixed(2) + "%) ";
			addChild(logger);
		}
 
		/**
		* Start the worker thread
		*/
		private function startWorkerThread(): void
		{
			// Get the bytes to work on and the Condition that controls access
			// to the bytes
			var bytes:ByteArray = Worker.current.getSharedProperty("bytes");
			var condition:Condition = Worker.current.getSharedProperty("condition");
 
			// Lock the condition mutex. This will suspend the worker until the
			// main thread calls wait() on the condition.
			condition.mutex.lock();
 
			// We have locked the mutex, which is our signal that resource it
			// represents is available to be worked on. In this case, that means
			// that the ByteArray has been set up and is ready to be compressed.
			bytes.compress();
 
			// We've finished our work on the ByteArray, so we can notify the
			// main worker that it's ready. Note that calling notify() does not
			// release the lock on the Condition's mutex
			condition.notify();
 
			// Unlock the mutex so other workers can use the shared ByteArray
			condition.mutex.unlock();
		}
	}
}

Run the example

Spot a bug? Know of other examples of Condition or want to provide your own? Post a comment!