美文网首页项目常见崩溃
项目常见崩溃12(陆续更新)

项目常见崩溃12(陆续更新)

作者: bigParis | 来源:发表于2018-08-21 19:22 被阅读33次

    说起死锁, 可能很多人都懂其中的原理, 但是却很少有人真正解决甚至遇到过死锁, 最近有幸真的处理了一次死锁.

    <_NSCallStackArray 0x2825f4930>(
    0   ???                                 0x000000010af10578 0x0 + 4478535032,
    1   Hago                                0x0000000104712800 main + 0,
    2   libdispatch.dylib                   0x0000000107462ef4 dispatch_once_f + 212,
    3   Hago                                0x0000000104c6f474 +[HGNetworkMonitorSvc sharedObject] + 92,
    4   Hago                                0x0000000104c6e244 +[HGNetworkMonitorSvc isReachable] + 52,
    5   Hago                                0x0000000104968a24 -[HGTransmitService onNetworkingReachabilityDidChangeNotification:] + 76,
    6   CoreFoundation                      0x00000001844a0d00 <redacted> + 20,
    7   CoreFoundation                      0x00000001844a0ccc <redacted> + 64,
    8   CoreFoundation                      0x00000001844a01bc <redacted> + 392,
    9   CoreFoundation                      0x000000018449fe68 <redacted> + 96,
    10  CoreFoundation                      0x0000000184418310 <redacted> + 1404,
    11  CoreFoundation                      0x000000018449f8f4 _CFXNotificationPost + 696,
    12  Foundation                          0x0000000184eaa030 <redacted> + 68,
    13  Hago                                0x0000000104c6ef08 -[HGNetworkMonitorSvc init] + 1568,
    14  Hago                                0x0000000104c6f4dc __35+[HGNetworkMonitorSvc sharedObject]_block_invoke + 68,
    15  libdispatch.dylib                   0x0000000107460eac _dispatch_client_callout + 16,
    16  libdispatch.dylib                   0x0000000107462e98 dispatch_once_f + 120,
    17  Hago                                0x0000000104c6f474 +[HGNetworkMonitorSvc sharedObject] + 92,
    18  Hago                                0x0000000104c75678 -[HGAppModule handleFirstPageAppearCallback] + 52,
    19  Hago                                0x0000000104c75144 __25-[HGAppModule initModule]_block_invoke_2 + 48,
    20  libdispatch.dylib                   0x0000000107460eac _dispatch_client_callout + 16,
    21  libdispatch.dylib                   0x0000000107462e98 dispatch_once_f + 120,
    22  Hago                                0x0000000104c750b0 __25-[HGAppModule initModule]_block_invoke + 196,
    23  Hago                                0x0000000104c75594 __24-[HGAppModule delayInit]_block_invoke + 636,
    24  libdispatch.dylib                   0x0000000107460eac _dispatch_client_callout + 16,
    25  libdispatch.dylib                   0x0000000107462e98 dispatch_once_f + 120,
    26  Hago                                0x0000000104c752d8 -[HGAppModule delayInit] + 164,
    27  Hago                                0x00000001046bd06c __36-[HGTabBarController viewDidAppear:]_block_invoke + 88,
    28  libdispatch.dylib                   0x0000000107460eac _dispatch_client_callout + 16,
    29  libdispatch.dylib                   0x0000000107462e98 dispatch_once_f + 120,
    30  Hago                                0x00000001046bcfe8 -[HGTabBarController viewDidAppear:] + 408,
    31  UIKitCore                           0x00000001b114b1e4 <redacted> + 808,
    32  UIKitCore                           0x00000001b0d3df38 <redacted> + 200,
    33  Hago                                0x0000000104a19434 -[HGNavigationViewController viewDidAppear:] + 80,
    34  UIKitCore                           0x00000001b114b1e4 <redacted> + 808,
    35  UIKitCore                           0x00000001b114b600 <redacted> + 264,
    36  CoreFoundation                      0x0000000184418754 <redacted> + 144,
    37  UIKitCore                           0x00000001b114b390 <redacted> + 1236,
    38  UIKitCore                           0x00000001b114db78 <redacted> + 44,
    39  UIKitCore                           0x00000001b114c1bc <redacted> + 92,
    40  UIKitCore                           0x00000001b0a8f848 <redacted> + 564,
    41  UIKitCore                           0x00000001b0a7d77c <redacted> + 384,
    42  UIKitCore                           0x00000001b0a9e2b4 <redacted> + 152,
    43  CoreFoundation                      0x00000001844c23f4 <redacted> + 20,
    44  CoreFoundation                      0x00000001844c1cf4 <redacted> + 272,
    45  CoreFoundation                      0x00000001844bcce8 <redacted> + 1060,
    46  CoreFoundation                      0x00000001844bc5a4 CFRunLoopRunSpecific + 436,
    47  GraphicsServices                    0x000000018672a584 GSEventRunModal + 100,
    48  UIKitCore                           0x00000001b0a83b04 UIApplicationMain + 212,
    49  Hago                                0x00000001047128a4 main + 164,
    50  libdyld.dylib                       0x0000000183f7cdc8 <redacted> + 4
    

    这次死锁的原因是HGNetworkMonitorSvc是一个单例, 但是我却在这个单例里面发了一个通知, 更不巧的是, 这个通知又用到了HGNetworkMonitorSvc这个单例, 就导致了死锁.

    #define IMPLEMENT_SIGNALTON(__TYPE__)       \
    + (instancetype)sharedObject {              \
    static dispatch_once_t __once;              \
    static __TYPE__ * __instance = nil;         \
    dispatch_once(&__once, ^{                   \
        __instance = [[__TYPE__ alloc] init];   \
    });                                         \
    return __instance;                          \
    }
    

    相信100个iOS开发99个都是用这种方式来创建单例的吧, 但是dispatch_once在进行实例初始化的时候, 实际上对__once进行了加锁, 这里刚好在init方法里做了如下的操作.

    - (instancetype)init
    {
        if (self = [super init]) {
            GLobalRealReachability.autoCheckInterval = 10.f;
            GLobalRealReachability.pingTimeout = 10;
            [GLobalRealReachability startNotifier];
            ReachabilityStatus status = GLobalRealReachability.currentReachabilityStatus;
            WWANAccessType wwanType = GLobalRealReachability.currentWWANtype;
            GLobalRealReachability.hostForPing = @"https://i-863.ihago.net/d/_ping";
            _networkType = [self getPKNetworkTypeFromRealStatus:status wwanType:wwanType];
            _realNetworkType = _networkType;
            MFLogInfo(@"NetWork", @"network initial:%@", @(_networkType));
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(networkChanged:)
                                                         name:kRealReachabilityChangedNotification
                                                       object:nil];
            PKNetworkType aPreNetworkType = [self refreshNetworkType:status wwanType:wwanType];
            [BS_NotifyCenter postNotificationName:kMFNetworkingReachabilityDidChangeNotification
                                           object:nil
                                         userInfo:@{ kMFNetworkingReachabilityNotificationStatusItem : @(self.networkType),
                                                     kMFNetworkingReachabilityNotificationStatusBeforeItem : @(aPreNetworkType) }];
            [self initNetworkMonitor];
        }
        return self;
    }
    

    kMFNetworkingReachabilityDidChangeNotification通知最终会触发

    - (void)onNetworkingReachabilityDidChangeNotification:(NSNotification *)notification
    {
        BOOL isReachable = [HGNetworkMonitorSvc isReachable];
        MFLogInfo(LogTag, @"onNetworkingReachabilityDidChangeNotification:%d", isReachable);
        PKNetworkType beforeStatus = (PKNetworkType)[notification.userInfo[kMFNetworkingReachabilityNotificationStatusBeforeItem] longLongValue];
    
        if (isReachable && beforeStatus == PKNetwork_NotReachable) {
            [self onChannleOrNetReady];
        } else if (!isReachable && beforeStatus != PKNetwork_Unknown) {
            [self onChannleOrNetBreak];
        }
    }
    
    HGNetworkMonitorSvc.m
    + (BOOL)isReachable
    {
        return [HGNetworkMonitorSvc sharedObject].realNetworkType != PKNetwork_Unknown &&
        [HGNetworkMonitorSvc sharedObject].realNetworkType != PKNetwork_NotReachable;
    }
    

    这里又用了HGNetworkMonitorSvc, 就造成了死锁, 因为都是在主线程执行的, 在init前, 系统对__once加锁, 当init经过一波操作同步调用了HGNetworkMonitorSvcsharedObject, 这时候__once已经加锁, 无法访问, 主线程因此卡死, 死锁行程.

    解决的办法, 应该尽量避免在单例的init里发通知, 即便发通知也最好dispatch一下

            dispatch_async(dispatch_get_main_queue(), ^{
                [BS_NotifyCenter postNotificationName:kMFNetworkingReachabilityDidChangeNotification
                                               object:nil
                                             userInfo:@{ kMFNetworkingReachabilityNotificationStatusItem : @(self.networkType),
                                                         kMFNetworkingReachabilityNotificationStatusBeforeItem : @(aPreNetworkType) }];
            });
    

    这样就会把通知放到下次runloop去执行, 不会阻塞当前线程了.

    相关文章

      网友评论

        本文标题:项目常见崩溃12(陆续更新)

        本文链接:https://www.haomeiwen.com/subject/ggajiftx.html