What GCD queue, main or not, am I running on?

十年热恋 提交于 2019-11-30 09:09:33

Updated answer:

The Apple docs have changed and now say "When called from outside of the context of a submitted block, this function returns the main queue if the call is executed from the main thread. If the call is made from any other thread, this function returns the default concurrent queue." so checking dispatch_get_main_queue() == dispatch_get_current_queue() should work.

Original answer:

Using dispatch_get_main_queue() == dispatch_get_current_queue() won't work. The docs for dispatch_get_current_queue say "When called outside of the context of a submitted block, this function returns the default concurrent queue". The default concurrent queue is not the main queue.

[NSThread isMainThread] should work for what you want. Note that [NSThread isMainThread] can be true for for queues other than the main queue though, e.g., when calling dispatch_sync from the main thread.

With depreciation of dispatch_get_current_queue(), the equivalent of (dispatch_get_main_queue() == dispatch_get_current_queue())

is now by queue label comparison which is:

(dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))

Updated answer:

dispatch_get_current_queue() is now deprecated.

Original answer:

On OS-X 10.8, in the header file (queue.h), in the comment above the dispatch_get_current_queue() function, it is written:

When dispatch_get_current_queue() is called on the main thread, it may or may not return the same value as dispatch_get_main_queue(). Comparing the two is not a valid way to test whether code is executing on the main thread.

I discovered that because of an

assert(dispatch_get_current_queue() == dispatch_get_main_queue());

in my code that works well on iOS but fails on OS-X.

If you are in Objective-C and you want something to happen on the main thread synchronously, would it not be simpler to use

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

This has the advantage that, if you are already on the main thread, it doesn't matter, the message is sent in the normal way.

Madhup Singh Yadav

It's not safe to use dispatch_get_current_queue() except you are not debugging. As it is clearly written in the dispatch_queue man page:

CAVEATS

Code cannot make any assumptions about the queue returned by dispatch_get_current_queue(). The returned queue may have arbitrary policies that may surprise code that tries to schedule work with the queue. The list of policies includes, but is not limited to, queue width (i.e. serial vs. concurrent), scheduling priority, security credential or filesystem configuration. Therefore, dispatch_get_current_queue() MUST only be used for identity tests or debugging.

The better thing (may be more complicated) is to sync the background threads:

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

Maybe I am totally wrong, but that is what I suggest.

New way for macOS: 10.12 and iOS: 10.0 (tvOS: 10.0, watchOS:3.0) and later.

ObjC: Check if running on main queue:

if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {
           NSLog(@"Running on main queue");
}

Assert if running on main queue:

dispatch_assert_queue(dispatch_get_main_queue());

Assert if NOT running on main queue:

dispatch_assert_queue_not(dispatch_get_main_queue());

Swift 3, 4 and later:

Check if running on main queue (there is no direct method unfortunately):

if (OperationQueue.current?.underlyingQueue?.label == DispatchQueue.main.label) {
    print("On main queue")
}

Assert if running on main queue:

dispatchPrecondition(condition: .onQueue(.main))
// Code running on main queue

Assert if NOT running on main queue:

dispatchPrecondition(condition: .notOnQueue(.main))
// Code NOT running on main queue

NOTE: mainThread != mainQueue The main queue always runs on the main thread, but a queue may be running on the main thread without being the main queue. So, don't mix thread and queue tests!

Actually, it is OK to use.

The documentation says

When called from outside of the context of a submitted block, this function returns the main queue if the call is executed from the main thread. If the call is made from any other thread, this function returns the default concurrent queue.

Note that the main queue is not the same as the main thread. It is easily possible for a non-main queue to be operating on the main thread, when dispatch_sync() is used on a queue from the main thread. Much more rarely, in command-line tools which use dispatch_main() in lieu of NSRunLoops (i.e., other than Cocoa/iOS applications), it's possible for the main queue to execute in something other than the main thread.

If you are dealing with code that requires the main queue and not just the main thread (say code which expects values it set on the main queue from queue_get_specific, which VectorKit/MapKit have been rumored to do), it is better to check for the main queue explicitly rather than the main thread.

One option to explicitly check for the main queue:

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;
}

The answer using DISPATCH_CURRENT_QUEUE_LABEL should also work and is probably better, though may not work (i.e. crash) before MacOS 10.9 and iOS7, when DISPATCH_CURRENT_QUEUE_LABEL was defined.

dispatch_get_current_queue is deprecated as of iOS 6.0. Looks like [NSThread isMainThread] is the only way to go.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!