В какой очереди GCD, основной или нет, я работаю?
Я пытаюсь написать несколько потоковых методов, поэтому я использую:
...
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main,^{
[self doSomethingInTheForeground];
});
...
Но если я нахожусь в главном потоке, который не нужен, и я могу пропустить все эти вызовы диспетчеризации, поэтому я хотел бы знать, в каком потоке я в данный момент нахожусь. Как я могу это знать?
Или, возможно, это не имеет значения (в производительности), делая это?
Это нормально, чтобы сделать это сравнение?
if (dispatch_get_main_queue() == dispatch_get_current_queue()){...}
8 ответов
Обновленный ответ:
Документы Apple изменились и теперь говорят: "При вызове извне контекста переданного блока эта функция возвращает основную очередь, если вызов выполняется из основного потока. Если вызов сделан из любого другого потока, эта функция возвращает параллельная очередь по умолчанию. " так проверка dispatch_get_main_queue() == dispatch_get_current_queue()
должно сработать.
Оригинальный ответ:
С помощью dispatch_get_main_queue() == dispatch_get_current_queue()
не сработает Документы для dispatch_get_current_queue
сказать "При вызове вне контекста переданного блока эта функция возвращает параллельную очередь по умолчанию". Параллельная очередь по умолчанию не является основной.
[NSThread isMainThread]
должен работать на то, что вы хотите. Обратите внимание, что [NSThread isMainThread]
может быть истинным для очередей, отличных от основной очереди, хотя, например, при вызове dispatch_sync
из основного потока.
С амортизацией dispatch_get_current_queue()
, эквивалент (dispatch_get_main_queue() == dispatch_get_current_queue())
Теперь по сравнению метки очереди:
(dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))
Обновленный ответ:
dispatch_get_current_queue() теперь устарела.
Оригинальный ответ:
На OS-X 10.8 в заголовочном файле (queue.h) в комментарии над функцией dispatch_get_current_queue() написано:
Когда dispatch_get_current_queue() вызывается в главном потоке, он может возвращать или не возвращать то же значение, что и dispatch_get_main_queue(). Сравнение двух не является допустимым способом проверить, выполняется ли код в главном потоке.
Я обнаружил, что из-за
assert(dispatch_get_current_queue() == dispatch_get_main_queue());
в моем коде, который хорошо работает на iOS, но не работает на OS-X.
Новый способ для macOS: 10.12 и iOS: 10.0 (tvOS: 10.0, watchOS:3.0) и выше.
ObjC: проверить, работает ли в главной очереди:
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {
NSLog(@"Running on main queue");
}
Подтвердить, если работает в главной очереди:
dispatch_assert_queue(dispatch_get_main_queue());
Подтвердить, если не работает в основной очереди:
dispatch_assert_queue_not(dispatch_get_main_queue());
Свифт 3, 4 и позже:
Проверьте, работает ли в главной очереди (прямого метода, к сожалению, нет):
if (OperationQueue.current?.underlyingQueue?.label == DispatchQueue.main.label) {
print("On main queue")
}
Подтвердить, если работает в главной очереди:
dispatchPrecondition(condition: .onQueue(.main))
// Code running on main queue
Подтвердить, если не работает в основной очереди:
dispatchPrecondition(condition: .notOnQueue(.main))
// Code NOT running on main queue
НОТА:
mainThread != mainQueue
Основная очередь всегда выполняется в главном потоке, но очередь может выполняться в главном потоке, не будучи основной очередью. Так что не смешивайте тесты потоков и очередей!
Если вы находитесь в Objective-C и хотите, чтобы что-то происходило в главном потоке синхронно, было бы проще использовать
[self performSelectorOnMainThread: @selector(doSomethingInTheForeground)
withObject: nil
waitUntilDone: YES];
Это имеет то преимущество, что, если вы уже находитесь в главном потоке, это не имеет значения, сообщение отправляется обычным способом.
Это не безопасно использовать dispatch_get_current_queue()
кроме как ты не отлаживаешь. Как это ясно написано в dispatch_queue
справочная страница:
ПРЕДОСТЕРЕЖЕНИЯ
Код не может делать никаких предположений об очереди, возвращаемой
dispatch_get_current_queue()
, Возвращенная очередь может иметь произвольные политики, которые могут удивить код, который пытается запланировать работу с очередью. Список политик включает, но не ограничивается, ширину очереди (то есть последовательная или параллельная), приоритет планирования, учетные данные безопасности или конфигурацию файловой системы. Следовательно,dispatch_get_current_queue()
ДОЛЖЕН использоваться только для проверки личности или отладки.
Лучшая вещь (может быть более сложная) состоит в синхронизации фоновых потоков:
dispatch_sync(backgroundqueue,^{
[self doSomethingInTheBackground];
});
Может быть, я совершенно не прав, но это то, что я предлагаю.
Обратите внимание, что основная очередь отличается от основного потока. Можно легко работать с неосновной очередью в главном потоке, когда dispatch_sync() используется в очереди из основного потока. Гораздо реже, в инструментах командной строки, которые используют dispatch_main() вместо NSRunLoops (то есть, кроме приложений Какао /iOS), главная очередь может выполняться в чем-то отличном от основного потока.
Если вы имеете дело с кодом, который требует основную очередь, а не только основной поток (скажем, код, который ожидает значения, установленные в главной очереди, из queue_get_specific, что, по слухам, должен делать VectorKit/MapKit), лучше проверить Основная очередь явно, а не основной поток.
Один из вариантов явной проверки основной очереди:
BOOL MyIsMainQueue(void)
{
static char MAIN_IND_KEY;
static char MAIN_IND_VAL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dispatch_queue_set_specific(dispatch_get_main_queue(), &MAIN_IND_KEY, &MAIN_IND_VAL, NULL);
});
return dispatch_get_specific(&MAIN_IND_KEY) == &MAIN_IND_VAL;
}
Ответ, использующий DISPATCH_CURRENT_QUEUE_LABEL, также должен работать и, вероятно, лучше, хотя может и не работать (то есть зависать) до MacOS 10.9 и iOS7, когда определено DISPATCH_CURRENT_QUEUE_LABEL.
На самом деле, это нормально использовать.
В документации сказано
При вызове извне контекста переданного блока эта функция возвращает основную очередь, если вызов выполняется из основного потока. Если вызов сделан из любого другого потока, эта функция возвращает параллельную очередь по умолчанию.
dispatch_get_current_queue
устарела с iOS 6.0. Похоже [NSThread isMainThread]
это единственный путь.