dispatch_group_wait永远等待

时间:2016-12-04 10:47:39

标签: objective-c multithreading macos grand-central-dispatch objective-c-blocks

我正在研究dispatch_async()的工作原理。

我在main()中尝试了这个代码段:

typedef void(^VoidBlock)();

VoidBlock aBlock = ^{
    NSLog(@"do work in main queue");
};
dispatch_async(dispatch_get_main_queue(), aBlock);

但是Block从未被调用过。我想也许主线程在块运行之前就结束了。 然后我尝试了这个:

dispatch_group_t aGroup = dispatch_group_create();
VoidBlock aBlock = ^{
    NSLog(@"do work in main queue");
    dispatch_group_leave(aGroup);
};
dispatch_group_enter(aGroup);
dispatch_async(dispatch_get_main_queue(), aBlock);
dispatch_group_wait(aGroup, DISPATCH_TIME_FOREVER);

这也不起作用(Block不会被调用)。 区别在于现在主要线程(正确)阻塞了语句dispatch_group_wait(aGroup, DISPATCH_TIME_FOREVER)

有什么问题?

2 个答案:

答案 0 :(得分:4)

我怀疑您没有创建iOS项目(或任何其他触发runloop的项目类型),而是“命令行工具”。如果是这种情况:

您的第一个方法

一般情况下,您的第一种方法很好,但在触发异步调用之前,main()会返回(因此您的应用已完成运行)。

您的第二种方法

您在第二种方法中得到了正确的想法:等到您的异步作业完成。

您的实现虽然导致死锁。 wait阻止从它(主线程)调用它的线程,直到你的块完成运行,但是当主线程被阻塞时块永远不会运行。

<强>解决方案

要解决此问题,请在与等待队列不同的队列上发送:

dispatch_group_t aGroup = dispatch_group_create();
VoidBlock aBlock = ^{
      NSLog(@"do work in main queue");
      dispatch_group_leave(aGroup);
};
dispatch_group_enter(aGroup);

 // dispatch on another queue than the one wait will block
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), aBlock);
dispatch_group_wait(aGroup, DISPATCH_TIME_FOREVER);

这样主队列就等待(阻塞),而你的块可以在另一个队列上执行。

@Ishahaks answer创建“单一视图应用程序”而不是“命令行工具”也可以工作(因为问题原来被称为“iOS”),即使在main()中也是如此。因此,iOS应用程序触发了一个runloop(while(true) { // wait for events }),因此应用程序在从main()返回后仍然运行。请参阅Apples Runloop Documentation

答案 1 :(得分:0)

如果您正在为iOS开发,请使用&#34; New&#34; &#34;项目&#34; &#34;单一视图应用程序&#34;,然后将您的代码放入application:didFinishLaunchingWithOptions,如下所示:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    typedef void(^VoidBlock)();

    VoidBlock aBlock = ^{
        NSLog(@"do work in main queue");
    };
    dispatch_async(dispatch_get_main_queue(), aBlock);
    return YES;
}