В какой очереди GCD, основной или нет, я работаю? - PullRequest
9 голосов
/ 09 февраля 2011

Я пытаюсь написать несколько потоковых безопасных методов, поэтому я использую:

...
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main,^{
  [self doSomethingInTheForeground];
});
...

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

Или, возможно, это не имеет значения (в производительности), делая это?

Можно ли проводить это сравнение?

if (dispatch_get_main_queue() == dispatch_get_current_queue()){...}

Ответы [ 9 ]

12 голосов
/ 11 февраля 2011

Обновленный ответ :

Документы 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 из основного потока.

11 голосов
/ 08 января 2016

С амортизацией 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))
4 голосов
/ 24 ноября 2012

Обновленный ответ:

dispatch_get_current_queue () теперь устарел.

Оригинальный ответ:

В OS-X10.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.

2 голосов
/ 09 февраля 2011

Если вы находитесь в Objective-C и хотите, чтобы что-то происходило в главном потоке синхронно, было бы проще использовать

[self performSelectorOnMainThread: @selector(doSomethingInTheForeground) 
                       withObject: nil 
                    waitUntilDone: YES];

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

1 голос
/ 31 января 2019

Новый способ для 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 Основная очередь всегда выполняется на главной поток, но очередь может быть запущена в основном потоке без основная очередь. Поэтому не смешивайте тесты потоков и очередей!

1 голос
/ 09 февраля 2011

Использование dispatch_get_current_queue() небезопасно, кроме случаев, когда вы не отлаживаете. Как ясно написано в справочной странице dispatch_queue :

ПРЕДОСТЕРЕЖЕНИЯ

Код не может делать какие-либо предположения относительно очереди, возвращаемой dispatch_get_current_queue(). Возвращенная очередь может иметь произвольные политики, которые могут удивить код, который пытается запланировать работу с очередью. Список политик включает, но не ограничивается ими, ширину очереди (то есть последовательная или параллельная), приоритет планирования, учетные данные безопасности или конфигурацию файловой системы. Следовательно, dispatch_get_current_queue() ДОЛЖЕН использоваться только для проверки личности или отладки.

Лучшая вещь (может быть более сложная) состоит в синхронизации фоновых потоков:

dispatch_sync(backgroundqueue,^{
  [self doSomethingInTheBackground];
});

Может быть, я совершенно не прав, но это то, что я предлагаю.

0 голосов
/ 26 мая 2018

Обратите внимание, что основная очередь не совпадает с основным потоком.Можно легко работать с неосновной очередью в основном потоке, когда 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.

0 голосов
/ 27 августа 2013

dispatch_get_current_queue устарела с iOS 6.0.Похоже, [NSThread isMainThread] - единственный путь.

0 голосов
/ 25 октября 2011

На самом деле, это нормально для использования.

В документации написано

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

...