dispatch_group_leave瓦解

手机游戏开发者 2024-9-7 18:34:34 100 0 来自 中国
瓦解形貌



克日排查线上瓦解时,发现一个形貌信息很少的瓦解,如上。由dispatch_group_leave.cold.1可知,属于dispatch_group非常
dispatch_group利用

dispatch_group利用场景:A任务依赖B/C/D子任务全部实验完成,才举行触发实验。
怎样添加子任务,通常有两种方式:

  • block
  • dispatch_group_enter+dispatch_group_leave
    dispatch_group_t group = dispatch_group_create();    // 添加N个子任务...    dispatch_group_enter(group);    dispatch_async(dispatch_get_global_queue(0, 0), ^{        // 耗时任务task1        dispatch_group_leave(self.group);    });    // ...        dispatch_group_notify(group, dispatch_get_main_queue(), ^{        NSLog(@"task123完成,收到通知");    });为什么dispatch_group_leave瓦解?

dispatch_group维持有一个计数。

  • dispatch_group_create初始化为LONG_MAX
  • dispatch_group_leave时+1
  • dispatch_group_enter时-1。
当leave次数超出enter次数时,LONG_MAX+1溢出,触发Crash。
陷阱规避

1. 属性记录dispatch_group_t,易引发错位leave

示例错误代码:
// 强引用group对象@property (nonatomic, strong) dispatch_group_t group;@property (nonatomic, strong) NSOperationQueue *queue;- (void)cancel {    self.cancelled = YES;    [self.queue cancelAllOperations];}- (void)exportImageNSArray<NSString *> *)infos {    self.group = dispatch_group_create();    self.cancelled = NO;        __weak typeof(self) weak_self = self;    for (NSString *info in infos) {        dispatch_group_enter(self.group);        [self.queue addOperationWithBlock:^{            // 大量盘算与io耗时操纵            // ...            dispatch_group_leave(weak_self.group);        }];    }    dispatch_group_notify(self.group, dispatch_get_main_queue(), ^{        if (!weak_self.cancelled) {            // 导出完成,下一步        }    });}- (NSOperationQueue *)queue {    if (!_queue) {        _queue = [[NSOperationQueue alloc] init];        _queue.maxConcurrentOperationCount = 2;    }    return _queue;}复现步调:
Demo,点击开始,4s内点击竣事再点击开始,等待一会,瓦解。
如果infos只有一条数据,单个导出任务耗时10s,任务A在举行到5s时,取消任务A,重新触发新的导出B,A/B均完成时,就会瓦解。
缘故因由分析:

  • NSOperationQueue已经调治的任务,实在是无法直接取消的,任务仍会继续实验
  • A任务再履历5s后完成,调用dispatch_group_leave(weak_self.group);,但实在A创建的group已开释,调用的是B的group.leave,计数为LONG_MAX,并触发notify。
  • 当B也完成任务时,再次调用dispatch_group_leave,导致瓦解。
2. 怎样规避?

dispatch_group_t改用局部变量即可。
示例精确代码:
// 强引用group对象@property (nonatomic, strong) NSOperationQueue *queue;- (void)cancel {    self.cancelled = YES;    [self.queue cancelAllOperations];}- (void)exportImageNSArray<NSString *> *)infos {    dispatch_group_t group = dispatch_group_create();    self.cancelled = NO;        __weak typeof(self) weak_self = self;    for (NSString *info in infos) {        dispatch_group_enter(group);        [self.queue addOperationWithBlock:^{            // 大量盘算与io耗时操纵            // ...            dispatch_group_leave(group);        }];    }    dispatch_group_notify(.group, dispatch_get_main_queue(), ^{        if (!weak_self.cancelled) {            // 导出完成,下一步        }    });}- (NSOperationQueue *)queue {    if (!_queue) {        _queue = [[NSOperationQueue alloc] init];        _queue.maxConcurrentOperationCount = 2;    }    return _queue;}
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-23 20:55, Processed in 0.178904 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表