Синхронизированные блоки и dispatch_async

Что происходит с блокировкой в ​​IOS с помощью @synchronized(), когда мы вызываем dispatch_async() внутри блока.

Для ex:

    id myID
-(void) foobar
{
    @synchronized(myID){
        dispatch_async(){ //do stuff with myID};
    }
}

Является ли блокировка по-прежнему действительной в вызове dispatch_async? Или, что еще более важно, есть ли недостатки в использовании другого вызова @synchronized() внутри dispatch_async()?

Ответ 1

Предполагая, что вы пытаетесь синхронизировать взаимодействие с этим объектом myID в фоновой очереди, вы хотите, чтобы это было наоборот, блокировка внутри отправленного блока. Сейчас у вас есть:

@synchronized(myID) {
    dispatch_async(queue, ^{
         // do stuff with myID
    });
}

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

Вероятно, вы планировали:

dispatch_async(queue, ^{
    @synchronized(myID) {
         // do stuff with myID
    }
});

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

В качестве дополнительного уточнения, если этот отправленный блок, возможно, медленный (и я предполагаю, что это может быть), тогда вы, вероятно, захотите максимально ограничить блок @synchronized:

dispatch_async(queue, ^{

    // do slow stuff in preparation for interacting with `myID`

    @synchronized(myID) {
         // quickly do stuff with myID
    }

    // do anything else here
});

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

Как окончательное наблюдение, если у вас есть последовательная очередь (или неглобальная параллельная очередь, в которой вы делаете обновления с барьером), которые часто используются в качестве метода, который полностью исключает необходимость блокировок, если все обновления и запросы для myID отправляются в эту очередь. См. Устранение кода блокировки в руководстве по программированию Concurrency.

Ответ 2

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

Итак, материал внутри блока не синхронизирован. Параметры для достижения минимальных изменений - это синхронная отправка или просто синхронизация в блоке.

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