SurfaceView threading – when Synchronized isn’t enough

I have been a server developer most of my career, writing 3-tier websites in Java. Somewhere along the way, I started to specialize in writing Services. The frameworks to write Services e.g. Spring are meant to hide the complexity of writing your own threads. All the servers take care of that complexity by threading the request way before you ever do anything with it. Spring tells you never to use class level variables to store data – instead use local variables or ThreadLocal. The pattern works for Server-side software.

For kids apps, I write client-side UI software. It is different. Any heavy-duty tasks must be offloaded from the main thread. Ability to handle threading is needed to build a responsive UI. I wrote a post on to build games using SurfaceView sometime back. The simple example there shows how to start using SurfaceView. Today, I am writing about how to process Touch events on this SurfaceView.

Which thread?

Touch events are generated on the main UI thread when the user interacts with the touch screen. The SurfaceView renders on the thread we create to render it (the rendering thread). To have an effect in the game, the touch event will change some variables in the SurfaceView – variables that may be accessed at the same time by the rendering thread. How do we process this safely without causing data corruption? The standard answer is to use synchronization.

Synchronization

Synchronization means only one thread can access anything designated as synchronized within an object at a time. Other threads have to wait. Synchronization implies locking, and locking implies reduced performance. Synchronizing the SurfaceView will slow down the rendering and reduce the number of frames rendered per second. Instead of synchronizing the objects being used to render the SurfaceView, we can pass the TouchEvents to the SurfaceView using a queue. The SurfaceView rendering thread will pick up any queued TouchEvents from the queue per rendering cycle, and process them. Synchronization is only needed to access the touch events queue. Implementation of one such queue using a recyclable Pool of touch events is in Beginning Android games by Mario Zechner.

Volatility

I used the TouchHandler code from Beginning Android Games by Mario Zechner. It worked well, but, when I tried it on my most powerful device (HTC one), the animations would jump around randomly at times or crash unexpectedly. The handoff was synchronized as shown in the code. We puzzled over it a while, till we found the answer –

Declare all primitives accessed by both threads (Main and SurfaceView threads) as volatile. If they are not declared volatile, there is no guarantee that the value set on one thread will be the same as the value read on another thread. Declaring as volatile is needed even if the variable access is synchronized.

For passing touch events from Main thread to SurfaceView rendering thread, the values in the TouchEvent must be declared volatile –


public class TouchEvent {
	public static final int TOUCH_DOWN = 0;
	public static final int TOUCH_MOVE = 1;
	public static final int TOUCH_UP = 2;

	volatile public int type;
	volatile public int x;
	volatile public int y;
	volatile public int pointer;	
}

This is what Core Java says about Volatile –

Computers with multiple processors can temporarily hold memory values in registers or local memory caches. As a consequence, threads running in different processors may see different values for the same memory location. If you declare the field as volatile, then the compiler and the virtual machine take into account that the field may be concurrently updated by another thread. Volatile variables do not provide atomicity.

The above is observable on multi-core android phones and tablets.

Atomic and Volatile

If you need to update the variable atomically and follow volatile semantics, use the Concurrent library. It is implemented in Android via AtomicInteger, AtomicBoolean, AtomicReference, etc.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s