iOS:在多个后台线程完成之前不要从函数返回

Posted

技术标签:

【中文标题】iOS:在多个后台线程完成之前不要从函数返回【英文标题】:iOS: Don't return from function until multiple background threads complete 【发布时间】:2013-05-12 22:59:51 【问题描述】:

这看起来应该很简单,但我遇到了很多麻烦。我有一个函数可以触发一堆在后台运行并具有完成块的其他函数。我希望我的函数等到所有完成块都被调用后才返回。

我无法控制我正在调用的在后台执行的函数。否则我只会修改它以将 dispatch_async 与我自己的队列一起使用,然后等待该队列完成。

我的情况示例:

- (void)functionThatShouldBeSynchronous 
    for (int i = 0; i < 10; i++) 
        [self doSomethingInBackground:^
            NSLog(@"completed!");
        ];
    
    // How do I wait until all 10 threads have completed before returning?


- (void)doSomethingInBackground:(void(^)())completion 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
        [NSThread sleepForTimeInterval:1.0f]; // Do stuff
        completion(); // Execute completion block
    );

提前致谢。

【问题讨论】:

无论你最终做什么,不要阻塞主线程 @bbum 只是出于好奇,这样做的潜在后果是什么? 充其量?响应速度差,动画不连贯。最坏的情况?如果你阻塞主线程足够长的时间,系统会在假设它被锁定的情况下杀死你的应用程序。 @bbum 谢谢,我想这似乎很合乎逻辑。很高兴知道。 【参考方案1】:

使用这样的调度组:

- (void)functionThatShouldBeSynchronous 
    dispatch_group_t taskGroup = dispatch_group_create();

    for (int i = 0; i < 10; i++) 
        dispatch_group_enter(taskGroup);
        [self doSomethingInBackground:^
            NSLog(@"completed!");
            dispatch_group_leave(taskGroup);
        ];
    

    // Waiting for threads
    dispatch_group_wait(taskGroup, DISPATCH_TIME_FOREVER);
    dispatch_release(taskGroup);

    // Background work complete

如果您希望等待线程超时,您可以将 dispatch_group_wait 行更改为此

// Waiting 10 seconds before giving up
if (dispatch_group_wait(taskGroup, dispatch_time(DISPATCH_TIME_NOW, 10000000000)) != 0) 
    // Timeout

参数以纳秒为单位。

正如 bbum 所说,您不应该阻塞主线程。在这种情况下,您可以这样做:

typedef void(^MyCompletionHandler)();
-(void)functionDoingBackgroundWorkWithCompletionHandler:(MyCompletionHandler)completionHandler 
    dispatch_group_t taskGroup = dispatch_group_create();

    for (int i = 0; i < 10; i++) 
        dispatch_group_enter(taskGroup);
        [self doSomethingInBackground:^
            NSLog(@"completed!");
            dispatch_group_leave(taskGroup);
        ];
    

    dispatch_queue_t waitingQueue = dispatch_queue_create("com.mycompany.myapp.waitingQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(waitingQueue, ^
        // Waiting for threads
        dispatch_group_wait(taskGroup, DISPATCH_TIME_FOREVER);
        dispatch_release(taskGroup);


        // Background work complete
        dispatch_async(dispatch_get_main_queue(), ^
            // Calling the completion handler on the main thread (If you like)
            completionHandler();
        );
        dispatch_release(waitingQueue);
    );

【讨论】:

以上是关于iOS:在多个后台线程完成之前不要从函数返回的主要内容,如果未能解决你的问题,请参考以下文章

iOs后台线程中的函数调用

试图了解 iOS 中后台线程行为的幕后情况

如何确定从iOS后台返回前台时加载哪个视图?

C++如何运行多个可以随时调用的后台函数线程?

带有 RAII 的 std::mutex 但在后台线程中完成和释放

你如何设置一些函数在后台线程中运行但保持正常的返回类型而不是 Task<int>?