10

I am trying to write some thread safe methods so I am using:

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

But If I am on the main thread that is not necessary, and I can skip all those dispatch calls, so I would like to know what thread I currently am on. How can I know this?

Or, perhaps it does not make difference (in performance) doing it?

Is it ok to do this comparison?

if (dispatch_get_main_queue() == dispatch_get_current_queue()){...}
jscs
  • 63,694
  • 13
  • 151
  • 195
nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • 2
    Not just less overhead using one of the techniques mentioned, but if you do a dispatch_sync to the same queue you're running on, you'll deadlock. dispatch_async would be okay. – smparkes Feb 11 '11 at 01:52
  • If you need a more generic solution to prevent deadlocking in libdispatch, check out these helpers. They _dont_ cover main_queue, just be careful with that. https://gist.github.com/1205760 – steipete Sep 09 '11 at 09:57
  • The question is quite good but the sample code is showing a deadlock pattern. Maybe it is better to be modified. – xi.lin May 05 '16 at 14:25

9 Answers9

13

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.

smparkes
  • 13,807
  • 4
  • 36
  • 61
  • 2
    Actually, it 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." – mikelikespie Oct 24 '11 at 21:10
  • 1
    Thank you so much for the update. I think this is the way we all expect it to work like :) – nacho4d Oct 25 '11 at 03:12
  • 4
    Looks like `dispatch_get_current_queue()` is deprecated now, what is an alternative? – Shizam Apr 12 '13 at 18:59
  • you should use dispatch_get_specific. See http://stackoverflow.com/a/15725847/412916 and the link to Apple forums in the comments. – Jano Sep 15 '13 at 21:47
12

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))
ambientlight
  • 7,212
  • 3
  • 49
  • 61
  • Note that dispatch_queue_get_label() returns a char *. Is it enough checking the pointer values returned by both calls ? Is a strcmp() call redundant ? – Bemipefe Mar 29 '20 at 16:21
4

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.

Gabriele Mondada
  • 497
  • 4
  • 14
3

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

Swift 4+:

Check if running on main queue:

if (RunLoop.current == RunLoop.main) {
    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

ObjC: Check if running on main queue:

if ([[NSRunLoop currentRunLoop] isEqual: [NSRunLoop mainRunLoop]]) {
    NSLog(@"Running on main");
} else {
    NSLog(@"Not running on main");
}
   

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());

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!

Sverrisson
  • 17,970
  • 5
  • 66
  • 62
2

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.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
1

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.

jscs
  • 63,694
  • 13
  • 151
  • 195
Madhup Singh Yadav
  • 8,110
  • 7
  • 51
  • 84
  • 4
    Clearly states "for identity tests" as okay. That's what the original question alluded to (though that won't work as I mentioned in my answer). – smparkes Feb 11 '11 at 01:21
0

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.

Carl Lindberg
  • 2,902
  • 18
  • 22
0

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.

mikelikespie
  • 5,682
  • 3
  • 31
  • 36
-1

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

Andrei Tchijov
  • 559
  • 5
  • 11
  • 1
    I saw usage of dispatch_get_main_queue in lots of tutorials and documentation from apple and third parties. It seems it is a very widely used function. I therefor challenge that it is deprecated in general. Can you give references? Is there a direct replacement strategy? – Daniel S. Aug 28 '13 at 14:43
  • 1
    you are correct, I cut/paste name of the function wrong. it is dispatch_get_current_queue which got deprecated. Sorry for confusion. However, the conclusion still holds. [NSThread isMainThread] is the only way to go (even though it is not always mean that you are in main queue). – Andrei Tchijov Aug 28 '13 at 17:47
  • Aha, also new for me, but yes I agree. :) – Daniel S. Aug 28 '13 at 19:03