Threading in Xamarin.iOS

The Xamarin.iOS runtime gives developers access to the .NET threading APIs, both explicitly when using threads (System.Threading.Thread, System.Threading.ThreadPool) and implicitly when using the asynchronous delegate patterns or the BeginXXX methods as well as the full range of APIs that support the Task Parallel Library.

Xamarin strongly recommends that you use the Task Parallel Library (TPL) for building applications for a few reasons:

  • The default TPL scheduler will delegate Task execution to the thread pool, which in turn will dynamically grow the number of threads needed as process takes place, while avoiding a scenario where too many threads end up competing for CPU time.
  • It is easier to think about operations in terms of TPL Tasks. You can easily manipulate them, schedule them, serialize their execution or launch many in parallel with a rich set of APIs.
  • It is the foundation for programming with the new C# async language extensions.

The thread pool will slowly grow the number of threads as needed based on the number of CPU cores available on the system, the system load and your application demands. You can use this thread pool either by invoking methods in System.Threading.ThreadPool or by using the default System.Threading.Tasks.TaskScheduler (part of the Parallel Frameworks).

Typically developers use threads when they need to create responsive applications and they do not want to block the main UI run loop.

Developing Responsive Applications

Access to UI elements should be limited to the same thread that is running the main loop for your application. If you want to make changes to the main UI from a thread, you should queue the code by using NSObject.InvokeOnMainThread, like this:

MyThreadedRoutine ()  
{  
    var result = DoComputation ();  

    // we want to update an object that is managed by the main
    // thread; To do so, we need to ensure that we only access
    // this from the main thread:

    InvokeOnMainThread (delegate {  
        label.Text = "The result is: " + result;  
    });
}

The above invokes the code inside the delegate in the context of the main thread, without causing any race conditions that could potentially crash your application.

Threading and Garbage Collection

In the course of execution, the Objective-C runtime will create and release objects. If objects are flagged for "auto-release" the Objective-C runtime will release those objects to the thread's current NSAutoReleasePool. Xamarin.iOS creates one NSAutoRelease pool for every thread from the System.Threading.ThreadPool and for the main thread. This by extension covers any threads created using the default TaskScheduler in System.Threading.Tasks.

If you create your own threads using System.Threading you do have to provide you own NSAutoRelease pool to prevent the data from leaking. To do this, simply wrap your thread in the following piece of code:

void MyThreadStart (object arg)
{
   using (var ns = new NSAutoReleasePool ()){
      // Your code goes here.
   }
}

Note: Since Xamarin.iOS 5.2 you do not have to provide your own NSAutoReleasePool anymore as one will be provided automatically for you.