In the last article we learned that a ByteArray shared between two workers also shares its length field but not its position field. This raises a followup question: what about when the length changes? Today’s article sees what happens when you change the length of a ByteArray that is shared between two ActionScript workers to see just how shared that length field really is.

To recap, here’s how you set up a shared ByteArray:

// Main thread
bytes.shareable = true;
worker.setSharedProperty("bytes", bytes);
 
// Worker thread
var bytes:ByteArray = Worker.current.getSharedProperty("bytes");

Setting shareable to true stops the ByteArray from being copied to the other worker. Instead, the other worker receives the “same” ByteArray. However, as we found out in the last article, this is not true: the position field is different in each worker. Instead, there are two ByteArray objects that share the same bytes.

Now to test just how well these two ByteArray objects are kept in sync with each other. What happens when you set the length in one worker? Does the other worker see the length change or is the length only set when the worker receives a shared ByteArray? How about when you call ByteArray.clear? Does that reset the other worker’s ByteArray to have a length of zero? The following app tests both of these scenarios:

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.ByteArray;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.system.MessageChannel;
	import flash.system.Worker;
	import flash.system.WorkerDomain;
 
	public class ByteArrayTest extends Sprite
	{
		private var logger:TextField = new TextField();
		private function log(msg:String): void
		{
			logger.appendText(msg+"\n");
		}
 
		private var bytes:ByteArray = new ByteArray();
		private var workerToMain:MessageChannel;
		private var mainToWorker:MessageChannel;
		private var worker:Worker;
 
		public function ByteArrayTest()
		{
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			if (Worker.current.isPrimordial)
			{
				startMainThread();
			}
			else
			{
				startWorkerThread();
			}
		}
 
		private function startMainThread(): void
		{
			bytes = new ByteArray();
			bytes.length = 20;
			bytes.shareable = true;
 
			log("Main thread created ByteArray with length: " + bytes.length);
 
			worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes);
			workerToMain = worker.createMessageChannel(Worker.current);
			workerToMain.addEventListener(Event.CHANNEL_MESSAGE, onWTM1);
			mainToWorker = Worker.current.createMessageChannel(worker);
			worker.setSharedProperty("mainToWorker", mainToWorker);
			worker.setSharedProperty("workerToMain", workerToMain);
			worker.setSharedProperty("bytes", bytes);
			worker.start();
		}
 
		private function startWorkerThread(): void
		{
			workerToMain = Worker.current.getSharedProperty("workerToMain");
			mainToWorker = Worker.current.getSharedProperty("mainToWorker");
			mainToWorker.addEventListener(Event.CHANNEL_MESSAGE, onMainToWorker);
			bytes = Worker.current.getSharedProperty("bytes");
 
			workerToMain.send("Worker thread starting up. Sees ByteArray length: " + bytes.length);
		}
 
		private function onWTM1(ev:Event): void
		{
			workerToMain.removeEventListener(Event.CHANNEL_MESSAGE, onWTM1);
			workerToMain.addEventListener(Event.CHANNEL_MESSAGE, onWTM2);
			log((ev.target as MessageChannel).receive());
 
			log("Main thread setting length to 40");
			bytes.length = 40;
			mainToWorker.send(true);
		}
 
		private function onWTM2(ev:Event): void
		{
			workerToMain.removeEventListener(Event.CHANNEL_MESSAGE, onWTM2);
			workerToMain.addEventListener(Event.CHANNEL_MESSAGE, onWTM3);
			log((ev.target as MessageChannel).receive());
 
			log("Main thread calling clear()");
			bytes.clear();
			mainToWorker.send(true);
		}
 
		private function onWTM3(ev:Event): void
		{
			log((ev.target as MessageChannel).receive());
		}
 
		private function onMainToWorker(ev:Event): void
		{
			workerToMain.send("Worker thread received message. Sees ByteArray length: " + bytes.length);
		}
	}
}

Here’s what the app prints out:

Main thread created ByteArray with length: 20
Worker thread starting up. Sees ByteArray length: 20
Main thread setting length to 40
Worker thread received message. Sees ByteArray length: 40
Main thread calling clear()
Worker thread received message. Sees ByteArray length: 0

As you can see, the length property seems to be kept in sync throughout both the set length and clear calls. Each time the worker thread sees the length property updated appropriately. Since communication between workers can be awkward, slow, or both, it’s a good thing that length is effectively shared between them automatically. The lack of sharing position, however, seems to be a point of debate.

Spot a bug? Have a suggestion or a question? Post a comment!