Потоки в Xamarin.iOS

Среда выполнения Xamarin.iOS предоставляет разработчикам доступ к API потоков .NET, как явным образом при использовании потоков (System.Threading.Thread, System.Threading.ThreadPool), так и неявно при использовании асинхронных шаблонов делегатов или методов BeginXXX, а также полного диапазона API, поддерживающих библиотеку параллельных задач.

Xamarin настоятельно рекомендует использовать библиотеку параллельных задач (TPL) для создания приложений по нескольким причинам:

  • Планировщик TPL по умолчанию делегирует выполнение задачи пулу потоков, что, в свою очередь, будет динамически увеличивать количество потоков, необходимых при выполнении процесса, избегая сценария, в котором слишком много потоков в конечном итоге конкурируют за время ЦП.
  • Проще думать об операциях с точки зрения задач TPL. Вы можете легко управлять ими, планировать их выполнение, сериализовать их выполнение или запускать многие параллельно с богатым набором API.
  • Это основа программирования с новыми расширениями языка асинхронного языка C#.

Пул потоков будет медленно увеличивать количество потоков по мере необходимости в зависимости от количества ядер ЦП, доступных в системе, загрузки системы и требований приложения. Этот пул потоков можно использовать либо путем вызова методов в System.Threading.ThreadPool или с помощью по умолчанию System.Threading.Tasks.TaskScheduler (часть Parallel Framework).

Как правило, разработчики используют потоки, когда им нужно создавать адаптивные приложения, и они не хотят блокировать основной цикл выполнения пользовательского интерфейса.

Разработка адаптивных приложений

Доступ к элементам пользовательского интерфейса должен быть ограничен тем же потоком, который выполняет основной цикл для приложения. Если вы хотите внести изменения в основной пользовательский интерфейс из потока, следует ставить код в очередь с помощью NSObject.InvokeOnMainThread, как показано ниже.

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;  
    });
}

Приведенный выше код вызывает код внутри делегата в контексте основного потока, не вызывая каких-либо условий гонки, которые могут привести к сбою приложения.

Потоки и сборка мусора

Во время выполнения Objective-C среда выполнения создаст и освобождает объекты. Если объекты помечены для автоматического выпуска, Objective-C среда выполнения выпустит эти объекты в текущий поток NSAutoReleasePool. Xamarin.iOS создает один NSAutoRelease пул для каждого потока из System.Threading.ThreadPool основного потока. Это расширение охватывает все потоки, созданные с помощью taskScheduler по умолчанию в System.Threading.Tasks.

Если вы создаете собственные потоки, используя их, System.Threading необходимо предоставить собственный NSAutoRelease пул, чтобы предотвратить утечку данных. Для этого просто упаковайте поток в следующий фрагмент кода:

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

Примечание. Так как Xamarin.iOS 5.2 вам больше не нужно предоставлять собственный NSAutoReleasePool , так как он будет предоставлен автоматически для вас.