AFNetworking deadlock on tasks (tasksForKeyPath)

 ̄綄美尐妖づ 提交于 2019-12-10 18:13:12

问题


I'm sure this is something stupid that i'm doing, but after an hour I cannot see it. Maybe you can. Edit: this is on a device (iPhone 5S w/iOS 8.4), not the simulator.

I have an iOS 8 app with a DownloadManager, a singleton that subclasses AFHTTPSessionManager using a BackgroundSession. It used to work fine, but now I've done something and the result is that AFNetworking deadlocks in setDownloadTaskDidFinishDownloadingBlock, when I reference self.tasks.count:

[self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) {
    // POINT OF THIS BLOCK: RETURNS A FILENAME URL WHERE THE DOWNLOAD SHOULD GET STORED
    __strong typeof(self) strongSelf = weakS;
    if( !strongSelf )
        return nil;

    // deadlocks here on tasks.count
    DDLogVerbose(@"setDownloadTaskDidFinishDownloadingBlock, start; dataTasks - %lu, downloadTasks - %lu", (unsigned long)strongSelf.dataTaskManager.tasks.count, (unsigned long)strongSelf.tasks.count);

dataTaskManager refers to a separately subclassed AFHTTPSessionManager which is a standard session (not background) -- removing this from the logging line above does not solve the problem.

DownloadManager's completionQueue is set in init to be the same serial queue that the DownloadManager uses for everything:

    _processingQueue = dispatch_queue_create([[BUNDLE_IDENTIFIER stringByAppendingString:@".BackgroundSessionManager"] cStringUsingEncoding:NSUTF8StringEncoding], NULL);
    dispatch_queue_set_specific(_processingQueue, (__bridge const void *)(_processingQueue), (__bridge void *)(_processingQueue), NULL);
    self.completionQueue = _processingQueue; // set AFNetworking completionQueue to be our queue

... but that doesn't seem to help.

Here's the deadlock:

(lldb) bt all
  thread #1: tid = 0x137b14, 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8
    frame #1: 0x0000000198958c88 libsystem_kernel.dylib`mach_msg + 72
    frame #2: 0x00000001864eb724 CoreFoundation`__CFRunLoopServiceMachPort + 200
    frame #3: 0x00000001864e9678 CoreFoundation`__CFRunLoopRun + 940
    frame #4: 0x00000001864152d4 CoreFoundation`CFRunLoopRunSpecific + 396
    frame #5: 0x000000018fe736fc GraphicsServices`GSEventRunModal + 168
    frame #6: 0x000000018b012f40 UIKit`UIApplicationMain + 1488
    frame #7: 0x00000001000a60a4 Grab`main(argc=1, argv=0x000000016fd8ba80) + 124 at main.m:14
    frame #8: 0x000000019885aa08 libdyld.dylib`start + 4

  thread #2: tid = 0x137b6b, 0x0000000198958c24 libsystem_kernel.dylib`kevent64 + 8, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x0000000198958c24 libsystem_kernel.dylib`kevent64 + 8
    frame #1: 0x0000000100496588 libdispatch.dylib`_dispatch_mgr_invoke + 276
    frame #2: 0x000000010048709c libdispatch.dylib`_dispatch_mgr_thread + 52

  thread #3: tid = 0x137b6c, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992

  thread #6: tid = 0x137b6f, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992

* thread #7: tid = 0x137b97, 0x0000000198958e48 libsystem_kernel.dylib`semaphore_wait_trap + 8, queue = 'NSOperationQueue 0x17022f180 :: NSOperation 0x170449cf0 (QOS: LEGACY)'
    frame #0: 0x0000000198958e48 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000100494544 libdispatch.dylib`_dispatch_semaphore_wait_slow + 256
  * frame #2: 0x000000010018e8f4 Grab`-[AFURLSessionManager tasksForKeyPath:](self=0x0000000127d1e050, _cmd=0x0000000100203d49, keyPath=0x000000017042fdc0) + 340 at AFURLSessionManager.m:617
    frame #3: 0x000000010018ee88 Grab`-[AFURLSessionManager tasks](self=0x0000000127d1e050, _cmd=0x0000000191f79785) + 76 at AFURLSessionManager.m:623
    frame #4: 0x00000001000a8efc Grab`__36-[DownloadManager loadSessionBlocks]_block_invoke150(.block_descriptor=<unavailable>, session=0x0000000170132700, downloadTask=0x0000000127e408b0, location=0x00000001702bf860) + 328 at DownloadManager.m:149
    frame #5: 0x0000000100193734 Grab`-[AFURLSessionManager URLSession:downloadTask:didFinishDownloadingToURL:](self=0x0000000127d1e050, _cmd=0x000000018d2b4ddd, session=0x0000000170132700, downloadTask=0x0000000127e408b0, location=0x00000001702bf860) + 292 at AFURLSessionManager.m:1082
    frame #6: 0x0000000185f70b70 CFNetwork`__82-[NSURLSession delegate_downloadTask:didFinishDownloadingToURL:completionHandler:]_block_invoke + 40
    frame #7: 0x000000018741b1c4 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
    frame #8: 0x000000018736c604 Foundation`-[NSBlockOperation main] + 96
    frame #9: 0x000000018735c1cc Foundation`-[__NSOperationInternal _start:] + 636
    frame #10: 0x000000018741df28 Foundation`__NSOQSchedule_f + 228
    frame #11: 0x0000000100484f94 libdispatch.dylib`_dispatch_client_callout + 16
    frame #12: 0x000000010048fdb8 libdispatch.dylib`_dispatch_queue_drain + 780
    frame #13: 0x00000001004882c4 libdispatch.dylib`_dispatch_queue_invoke + 132
    frame #14: 0x00000001004925d4 libdispatch.dylib`_dispatch_root_queue_drain + 772
    frame #15: 0x0000000100494248 libdispatch.dylib`_dispatch_worker_thread3 + 132
    frame #16: 0x0000000198a0d22c libsystem_pthread.dylib`_pthread_wqthread + 816

  thread #12: tid = 0x137b9e, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992

  thread #10: tid = 0x137bf9, 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8, name = 'com.apple.NSURLConnectionLoader'
    frame #0: 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8
    frame #1: 0x0000000198958c88 libsystem_kernel.dylib`mach_msg + 72
    frame #2: 0x00000001864eb724 CoreFoundation`__CFRunLoopServiceMachPort + 200
    frame #3: 0x00000001864e9678 CoreFoundation`__CFRunLoopRun + 940
    frame #4: 0x00000001864152d4 CoreFoundation`CFRunLoopRunSpecific + 396
    frame #5: 0x0000000185ef2594 CFNetwork`+[NSURLConnection(Loader) _resourceLoadLoop:] + 440
    frame #6: 0x0000000187435db8 Foundation`__NSThread__main__ + 1072
    frame #7: 0x0000000198a0fdc8 libsystem_pthread.dylib`_pthread_body + 164
    frame #8: 0x0000000198a0fd24 libsystem_pthread.dylib`_pthread_start + 160

  thread #11: tid = 0x137bfa, 0x0000000198973498 libsystem_kernel.dylib`__select + 8, name = 'com.apple.CFSocket.private'
    frame #0: 0x0000000198973498 libsystem_kernel.dylib`__select + 8
    frame #1: 0x00000001864f1128 CoreFoundation`__CFSocketManager + 672
    frame #2: 0x0000000198a0fdc8 libsystem_pthread.dylib`_pthread_body + 164
    frame #3: 0x0000000198a0fd24 libsystem_pthread.dylib`_pthread_start + 160
(lldb) 

回答1:


.... I figured it out. Because of the way tasksForKeyPath is implemented, it is not possible to call .*tasks from the blocks like setTaskDidCompleteBlock, because the NSURLSession method underneath (getTasksWithCompletionHandler) will call back on the delegate queue, which is of course blocked by the original block like setTaskDidCompleteBlock. This sucks, but it's kinda Apple's fault I guess, for making the method that gets tasks asynchronous...

So the workaround is to avoid getting the current tasks from blocks like setTaskDidCompleteBlock (or anything that they call)



来源:https://stackoverflow.com/questions/31944465/afnetworking-deadlock-on-tasks-tasksforkeypath

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!