Как я могу проверить, что я запущен в заданной очереди GCD без использования dispatch_get_current_queue()?
Недавно мне потребовалась функция, которую я мог бы использовать, чтобы гарантировать синхронное выполнение данного блока в конкретной очереди последовательной отправки. Возможно, что эта общая функция может быть вызвана из уже запущенной в этой очереди, поэтому мне нужно было проверить этот случай, чтобы предотвратить тупик от синхронной отправки в одну очередь.
Для этого я использовал следующий код:
void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))
{
dispatch_queue_t videoProcessingQueue = [GPUImageOpenGLESContext sharedOpenGLESQueue];
if (dispatch_get_current_queue() == videoProcessingQueue)
{
block();
}
else
{
dispatch_sync(videoProcessingQueue, block);
}
}
Эта функция полагается на использование dispatch_get_current_queue()
для определения идентичности очереди, в которой эта функция работает, и сравнивает ее с целевой очередью. Если есть совпадение, он знает, как просто запустить встроенный блок без отправки в эту очередь, потому что функция уже запущена на нем.
Я слышал противоречивые вещи о том, правильно ли использовать dispatch_get_current_queue()
для выполнения подобных сравнений, и я вижу эту формулировку в заголовках:
Рекомендуется только для отладки и ведения журнала:
Код не должен делать никаких предположений о возвращенной очереди, если он не является одной из глобальных очередей или очереди, которые сам код создано. Код не должен предполагать, что синхронное выполнение на очередь находится в безопасности от тупиковой ситуации, если эта очередь не та, которая была возвращена dispatch_get_current_queue().
Кроме того, в iOS 6.0 (но еще не для Mountain Lion) заголовки GCD теперь отмечают эту функцию как устаревшую.
Похоже, я не должен использовать эту функцию таким образом, но я не уверен, что я должен использовать на своем месте. Для функции, подобной приведенной выше, ориентированной на основную очередь, я мог бы использовать [NSThread isMainThread]
, но как я могу проверить, запущен ли я в одной из моих пользовательских последовательных очередей, чтобы предотвратить блокировку?
Ответы
Ответ 1
Назначьте любой идентификатор, который вы хотите, с помощью dispatch_queue_set_specific()
. Затем вы можете проверить свой идентификатор с помощью dispatch_get_specific()
.
Помните, что dispatch_get_specific()
хорош, потому что он будет запускаться в текущей очереди, а затем подходить к целевым очередям, если ключ не установлен на текущем. Обычно это не имеет значения, но может быть полезно в некоторых случаях.
Ответ 2
Это очень простое решение. Это не так сильно, как использование dispatch_queue_set_specific
и dispatch_get_specific
вручную - у меня нет показателей.
#import <libkern/OSAtomic.h>
BOOL dispatch_is_on_queue(dispatch_queue_t queue)
{
int key;
static int32_t incrementer;
CFNumberRef value = CFBridgingRetain(@(OSAtomicIncrement32(&incrementer)));
dispatch_queue_set_specific(queue, &key, value, nil);
BOOL result = dispatch_get_specific(&key) == value;
dispatch_queue_set_specific(queue, &key, nil, nil);
CFRelease(value);
return result;
}