Posts Tagged ‘objective c’

Finding concurrency bugs in Objective C

Introduction to concurrency in Objective C

We can introduce concurrency to a process by creating threads. Within a process, threads use the same memory space and the same instruction set. Each thread has its own position within that instruction set. A thread is in one of 3 main states: running, ready, or blocked. Each thread has its own register state and its own call stack.

In OS X 10.6, Apple introduced Grand Central Dispatch, a thread pool technology that simplifies the use of threads. GCD introduces the concept of queues and tasks. A process can have multiple queues, where each queue has one or more blocks. A block is a task for execution on that queue. From a programming languages perspective, a block is a closure (a function plus a binding environment). As a user of the queue API, you simply dispatch blocks on the queue, and GCD manages the running of queues.

Behind the scenes, GCD will create and destroy threads as needed in order to handle the workload of the queues the user has created.

In the case of a serial queue, one block runs at a time. In the case of a concurrent queue, GCD may concurrently execute blocks placed on that queue on different threads.

There are two ways to place a block on a queue.

  • dispatch_sync places a block on a queue and waits until that block completes
  • dispatch_async places a block on a queue and continues immediately

Finding concurrency bugs in Objective C

In code that uses multiple queues, one common concurrency bug is deadlock. Deadlock can happen when there is contention between two queues.

One example of deadlock is when blocks on two separate queues make dispatch_sync calls to each other.

Let’s say we have two queues, the sending queue and the manager queue. The sending queue has a method called beginTransaction, and the manager queue, which oversees both sending and receiving, has methods for managing crypto keys, including one called updateCryptoKey.

beginTransaction looks like this:

make sure the transaction is valid
dispatch_async(sending queue, ^{
    ensure no other transactions are in progress
    get crypto keys for this transaction
    put the transaction in our data structure
    start the transaction
});

updateCryptoKey looks like this:

make sure key being submitted is valid
dispatch_sync(manager queue, ^{
    is there an existing key?
    if not, add the key
    if yes, remove the existing key and add the new key
});

There is a potential deadlock between the sending queue and the manager queue. Each block has a dependency on the other queue. For the block in beginTransaction, the step of getting the crypto keys will do a dispatch_sync to the manager queue. Meanwhile, for the block in the manager queue, the step of removing the existing keys will do a dispatch_sync to the sending queue as part of cancelling any existing transactions under the old key.

These queue dependencies aren’t immediately obvious, because they are hidden behind function calls.

When finding deadlock between queues, it doesn’t matter how a block got placed on a queue. Here we have one block that was placed using dispatch_async, and one that was placed using dispatch_sync. What matters is what happens once that block is running. Since these two blocks are on separate queues, they can be running simultaneously. Then one of them does a dispatch_sync to the other, and it waits, because that queue is not free at the moment. Then the other does a dispatch_sync back to the first, and it waits too, because that queue isn’t free either. This is a deadlock.

Being objective about Objective C

(Sorry, couldn’t resist the pun.) A few months ago, I started a new job that required me to learn Objective C and Cocoa/Cocoa Touch development on the Apple platform. In this post, I’ll relate a few concepts that I learned in other languages that crossed over to the Apple platform.

MVC architecture

In web app development, the view is (arguably) the DOM. The DOM is loaded at a certain point in time: when the browser is finished parsing the initial payload, a load event is generated, and as a developer you can specify a handler for this event. This allows you to do things when that view appears, like populate it with data.

In iOS, the load event is similar to viewWillAppear. A NSViewController subclass can implement this method to perform custom behavior when the view appears, such as updating the UI based on the contents of some property.

Connecting the view to the controller

In Cocoa/Cocoa Touch, outlets and actions are used to connect objects in the view with code in the controller. Outlets are for linking objects in the view to a property in the controller. This allows the controller to manipulate that object, for example, setting the title of a button object. Actions are triggered when an event happens to an object. For example, an action responds to a click on a button. Action methods are passed the sender of that action.

I would compare outlets to DOM objects, and I would compare actions to DOM event handlers. Xcode makes creating outlets and actions a drag and drop operation, but in Javascript, you use document.getElementById or jQuery. DOM events are attached to an object, and specify a callback function, which can also take an argument of the sender (the this keyword).

Event loops

An event loop handles all incoming events and allows the application to respond appropriately. More generally, an event loop takes a queue of messages and processes them one at a time. An example of a message would be “call this callback function”. Processing that message would be actually executing the callback. For example, in Javascript, you specify a callback for the click event. When the click happens, the message to call that callback is placed on the message queue. The loop processes messages one at a time, so if you have another Javascript function that is currently processing a table (maybe shading the rows), the click callback message will not be processed immediately.

The Cocoa main event loop, GLib main event loop, and Javascript event loop are conceptually the same.

Node.js uses a single-threaded Javascript event loop to great advantage. Using Node, it is fairly easy to implement a scalable, event-driven web application.

Cocoa extends the main event loop, allowing you to create other queues. Queues are event loops that may or may not run on another thread. However, messages dispatched on the same serial queue will always be executed one at a time. This allows you to protect variables that aren’t thread safe by only accessing them from a particular queue.

The Glib event loop is used by a GUI library such as Gtk+ to make a Linux application. I’ve used these libraries while fixing a few Gnucash bugs and while writing a Twitter client.

Conclusion

My experience with Gtk+ and Javascript allowed me to quickly pick up core Cocoa concepts and design patterns. Now if I could only remember to do all UI stuff on the main queue!