dispatch async vs dispatch порядок выполнения синхронизации

у меня есть очередь последовательной отправки, созданная с помощью:

dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL);

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

- (void)addObjectToQueue:(id)object
{
    dispatch_async(serialQueue, ^{
        // process object and add to queue
    }); 
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(serialQueue, ^{
        // work out return value
    });
    return returnValue;
} 

Если я вызову метод addObjectToQueue:, то немедленно вызовите метод isObjectInQueue:, они гарантированно будут выполняться в том же порядке, или будет/может isObjectInQueue выполнить первым?

In другими словами, dispatch_async выполняет точно то же самое, что и dispatch_sync (планирование блока немедленно), за исключением того, что он не блокирует вызывающий поток?

Я видел подобные вопросы с ответами в обоих направлениях, поэтому я ищу окончательный ответ, желательно подкрепленный документацией Apple.

2 ответов


гарантируется ли их выполнение в том же порядке?

да.

будет / может isObjectInQueue выполнить первым?

да.

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

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

другими словами, dispatch_async выполняет точно то же самое, что и dispatch_sync (планирование блока немедленно), за исключением того, что он не блокирует вызывающий поток?

Это верно. В обоих случаях блок добавляется в очередь. Это тут же добавил. dispatch_sync просто ждет завершения блока перед возвращением, тогда как dispatch_async сразу возвращается.


Я думаю, ваш вопрос в том, будет ли основной поток продолжать работать, пока dispatch_async все еще выполняется операция очереди? Я предполагаю, что это не будет, потому что это заслуживает прямого упоминания. Во всяком случае, я нашел это в dispatch_async.3 что предполагает, что это так:

концептуально, dispatch_sync() является удобной оболочкой вокруг dispatch_async() с добавлением семафора для ожидания завершение блока, и обертка вокруг блока сигнал о его завершение.

и действительно, если вы следуете исходный код dispatch_async в очереди.c вы увидите, что блок находится в очереди на переднем плане, и только после этого выполнение возвращается к коду, который вызвал dispatch_async. Поэтому, если очередь является последовательной,dispatch_async затем dispatch_sync из того же потока будет очередь блоков в порядке.

, потому что dispatch_sync будет блокировать до блока (и все блоки до в последовательная очередь) выполняются, тогда ваш код будет правильным. isObjectInQueue: правильно сообщит, если объект, добавленный ранее, находится в очереди.

редактировать: в многопоточной среде я бы написал код выше как:

- (void)addObjectToQueue:(id)object
{
    dispatch_barrier_async(_queue, ^{
        // process object and add to queue
    });
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(_queue, ^{
        // work out return value
    });
    return returnValue;
} 

потому что выполнение каждого метода может быть отложено в любой момент в пользу другого потока.