Что происходит с основной очередью / основным потоком, когда dispatch_sync выдается из основного потока, предназначенного для другой очереди отправки?

#ios #objective-c #multithreading #concurrency #grand-central-dispatch

#iOS #objective-c #многопоточность #параллелизм #grand-central-dispatch

Вопрос:

Предположим, я вызываю приведенный ниже метод в основном потоке. Если какой-либо другой поток выполняет запись в массив во время вызова метода, dispatch_sync заблокируется. Но он блокируется в другой очереди (не в основной очереди). Когда это заблокировано, каково состояние основной очереди (метод не может двигаться вперед, пока не вернется disaptch_sync, но рассматривается ли это как асинхронный вызов в основной очереди). очередь). Например: будет ли основная очередь реагировать на события пользовательского интерфейса? Если да, что произойдет с состоянием вызова метода, когда dispatch_sync возвращается, когда происходит реакция на событие пользователя?

 -(id) objectAtIndex:(NSUInteger)index
{
    __block id obj;
    dispatch_sync(self.dataAccessQ, ^{
        obj = self.embeddedArray[index];
    });
    return obj;
}
  

Ответ №1:

Не имеет значения, является ли это основной очередью или нет. Любая очередь, используемая для вызова objectAtIndex: , будет блокировать dispatch_sync вызов до его завершения.

Если вы вызываете этот код в основной очереди, он блокируется, как и любая другая очередь. В течение этого времени никакие пользовательские события обрабатываться не будут. Пользовательский интерфейс будет отображаться заблокированным в течение этого времени. По завершении пользовательский интерфейс снова будет работать в обычном режиме.

Комментарии:

1. Используя параллельную очередь, другие задачи в этой очереди могут продолжать выполняться.

2. @AminNegm-Awad Если objectAtIndex: вызывается из параллельной очереди, а параллельная очередь использует несколько потоков, то поток, используемый для обработки objectAtIndex: метода, будет заблокирован во время dispatch_sync использования. Другие потоки (если таковые имеются), используемые параллельной очередью, не будут затронуты. Но основная очередь — это последовательная очередь, поэтому ничего из этого не применяется.

3. Спасибо @rmaddy Итак, в заключение, если я создаю потокобезопасный массив, похоже, что я мало что могу сделать, кроме как спроектировать так, чтобы никакие записи не занимали слишком много времени.

4. Это было бы совсем другое обсуждение. Я бы провел некоторое исследование потокобезопасных массивов и, при необходимости, опубликовал новый вопрос, касающийся любых проблем, которые у вас есть с этим.

5. спасибо @rmaddy. Подойдет. Любые указатели на хороший дизайн потокобезопасного массива?

Ответ №2:

Нет, основная очередь тоже заблокирована.

Основная очередь привязана к основному потоку. Каждый поток может выполнять один и только один поток управления одновременно. Если какой-либо код выполняется в основном потоке, никакой другой код не может быть выполнен.

Поэтому ожидание результата операции, подписанной на другую очередь, заблокирует ожидающий поток. (Не параллельный Q!) Вот почему у нас есть обработчики завершения.

Вместо возврата объекта добавьте параметр для обработчика завершения в свой метод и вызовите его внутри блока в конце.

Комментарии:

1. Спасибо. Я пытаюсь создать потокобезопасный массив. Итак, мне нужно переопределить objectAtIndex и не могу добавить параметры. Какие-либо обходные пути для этого случая (например, подход блока завершения)?

2. Вам действительно следует еще раз подумать о том, чтобы иметь потокобезопасный массив. Это похоже на атомарные свойства, которые не решают большинство проблем с параллельным выполнением. Обычно вам нужен объект, управляющий содержимым массива, и очередь, которая позволяет вам сериализовать код, который шире простого доступа.