Objective c 调度组等待永远等待

Objective c 调度组等待永远等待,objective-c,multithreading,macos,grand-central-dispatch,objective-c-blocks,Objective C,Multithreading,Macos,Grand Central Dispatch,Objective C Blocks,我正在研究dispatch\u async()是如何工作的 我在main() 但这个街区永远不会被叫作。我想主线程可能在块运行之前结束。 然后我试了一下: dispatch_group_t aGroup = dispatch_group_create(); VoidBlock aBlock = ^{ NSLog(@"do work in main queue"); dispatch_group_leave(aGroup); }; dispatch_group_enter(aGro

我正在研究
dispatch\u async()
是如何工作的

我在
main()

但这个街区永远不会被叫作。我想主线程可能在块运行之前结束。 然后我试了一下:

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);
这也不起作用(块不会被调用)。 不同之处在于,现在主线程(正确地)阻塞了语句
dispatch\u group\u wait(aGroup,dispatch\u TIME\u FOREVER)


问题出在哪里?

如果您是为iOS开发的,那么请使用“新建”“项目”“单视图应用程序”,然后将代码放入
应用程序:使用选项完成启动,如下所示:

- (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项目(或触发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);
这样,主队列正在等待(阻塞),而您的阻塞可以在另一个队列上执行



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

您的意思是您在
main.m
文件中尝试了此代码吗?是的,当然是在
main.m
main
函数中!您在控制台上查看输出或甚至使用断点时尝试了什么?我在代码中没有发现任何问题。GCD定义了一个块类型
dispatch\u Block\t
,您可以使用它来代替自己创建
VoidBlock
类型。我将项目创建为
命令行工具
。为什么这是一个问题?其他队列(非主队列)的类似实验效果非常好!您没有运行循环,因此应用程序在退出
main()
后完成运行。不应与其他队列一起使用,如
dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u LOW,0)
dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u LOW,0)
!问题在于主队列。我认为这是因为当主线程在
dispatch\u group\u wait
状态下进入睡眠状态时,主线程中再也不能执行任何块了……我的意思是,您的第一种方法在dispatch\u QUEUE\u PRIORITY\u LOW状态下不起作用。我更新了答案,以减少误解。@shallow尽管你有一些深刻的想法,兄弟。:)回答得很好。
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);