我正在运行什么GCD队列,主要与否?

时间:2011-02-09 08:25:36

标签: objective-c multithreading cocoa grand-central-dispatch

我正在尝试编写一些线程安全的方法,所以我正在使用:

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

但是如果我在主线程上没有必要,我可以跳过所有这些调度调用,所以我想知道我目前在做什么线程。我怎么知道这个?

或者,也许它在性能方面没有差别?

可以进行这种比较吗?

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

9 个答案:

答案 0 :(得分:12)

更新回答

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]对于除主队列之外的队列可以为true,例如,当从主线程调用dispatch_sync时。

答案 1 :(得分:11)

折旧为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))

答案 2 :(得分:4)

更新回答:

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上运行失败。

答案 3 :(得分:2)

如果您在Objective-C中并且想要在主线程上同步发生某些事情,那么使用它会不会更简单

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

这样做的好处是,如果你已经在主线程上,那没关系,消息是以正常方式发送的。

答案 4 :(得分:1)

除非您没有调试,否则使用dispatch_get_current_queue()是不安全的。因为它写得很清楚in the dispatch_queue man page

  

CAVEATS

     

代码无法对dispatch_get_current_queue()返回的队列做出任何假设。返回的队列可能具有任意策略,可能会使尝试调度队列工作的代码感到惊讶。策略列表包括但不限于队列宽度(即串行与并发),调度优先级,安全凭证或文件系统配置。因此,dispatch_get_current_queue()必须仅用于身份测试或调试。

更好的事情(可能更复杂)是同步后台线程:

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

也许我完全错了,但这就是我的建议。

答案 5 :(得分:1)

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主队列始终在主队列上运行   线程,但是队列可能正在主线程上运行而没有被   主队列。因此,请勿混合使用线程和队列测试!

答案 6 :(得分:0)

实际上,可以使用。

文档说

  

当从提交的块的上下文外部调用时,这个   如果从main执行调用,函数将返回主队列   螺纹即可。如果调用是从任何其他线程进行的,则此函数   返回默认的并发队列。

答案 7 :(得分:0)

请注意,主队列与主线程不同。当在主线程的队列上使用dispatch_sync()时,非主队列很容易在主线程上运行。更常见的是,在使用dispatch_main()代替NSRunLoops的命令行工具中(即,除了Cocoa / iOS应用程序之外),主队列可以在主线程之外的其他内容中执行。< / p>

如果你正在处理需要主队列而不仅仅是主线程的代码(比如说代码需要在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时,可能无法正常工作(即崩溃)。

答案 8 :(得分:-1)

自iOS 6.0起,

dispatch_get_current_queue已被弃用。看起来[NSThread isMainThread]是唯一可行的方式。