dispatch_group_wait永远等待

dispatch_group_wait waits forever

我正在研究 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)

语句上

有什么问题?

如果您正在为 iOS 开发,则使用 "New" "Project" "Single View Application",然后像这样将您的代码放入 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;
}

我怀疑您没有创建 iOS 项目(或任何其他触发运行循环的项目类型),而是 "Command Line Tool"。如果是这样的话:

你的第一个方法

一般来说,您的第一种方法没问题,但是 main() returns(因此您的应用会在触发异步调用之前完成 运行)。

你的第二种方法

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

不过您的实施导致了死锁。 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);

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


to create a "Single View Application" instead of a "Command Line Tool" would also work (as the question was originally taged as "iOS"), even in main(). The reason therefore is that iOS applications trigger a runloop (while(true) { // wait for events }), so the application still runs after returning from main(). See Apples Runloop Documentation.