更新#3:这里是原始 github 问题的链接以及我们现在正在尝试的潜在解决方案...更新到 AFNetworking 1.3.0
https://github.com/AFNetworking/AFNetworking/issues/1054
更新#2:一旦我们进入这种死锁状态,它似乎可能在 [AFHTTPClient HTTPRequestOperationWithRequest:success:failure:] 方法中死亡。用 NSLogs 对其进行处理,并将问题发送给用户以查看它显示的内容。
更新#1:这是最近关于它发生时的旋转报告——这似乎指向了一些有趣的事情——有人对此有任何想法吗?
https://dl.dropboxusercontent.com/u/2053112/myapp_AFNetworking.spin
添加对 github.com/AFNetworking/AFNetworking/issues/907 的引用,因为代码非常接近。
另请注意,看门狗块能够检测并取消(即将失败)操作,但遗憾的是,即使它被取消,损坏已经造成并且应用程序死锁。
原帖:
我有以下情况,我想概述一下是否有其他人见过类似的情况。
我在 UIElement(仅限菜单栏项)MacOSX 应用程序中使用 AFNetworking,该应用程序枚举并使用文件系统事件来监视目录中的文件,然后处理这些文件并上传到服务器。这些文件存储在 Core Data 存储中并标记为需要上传等。
使用 GCD,我有 3 个循环执行的网络操作——每个操作触发下一个,最后一个再次触发该过程——所以一次只有一个处理。每次操作之间有 1-2 秒的延迟。这些操作之一 POST 以查看是否应上传文件。如果需要,下一个 PUT 文件。最后删除任何标记为删除的文件。PUT 是我的问题。
处理 PUT 的(类)方法在新创建的调度队列上调用,通过以下方式显式用于它:
dispatch_queue_t q_put = dispatch_queue_create("com.myapp.put", NULL);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * kPause), q_put, ^(void){
@autoreleasepool {
PUTfiles(completionBlock);
}
});
dispatch_release(q_put);
然后该方法创建一个 NSOperationQueue 和一个 NSBlockOperation,将其添加到队列中并让它离开。NSBlockOperation 是所有工作所在。基本上,这个块从 Core Data 获取文件 url,然后创建 PUT(通过 AFNetworking)并将其排队等待上传。详细地说,我正在创建一个 NSURLRequest 作为 PUT 并附有文件。然后创建一个 AFHTTPRequestOperation 并将其 enqueueHTTPRequestOperation 入队。
到目前为止,一切都很好。该过程实际上在大多数情况下运行良好。当 NSURLRequest 超时时,问题就出现了。60 秒后,如果 NSURLRequest 超时,AFNetworking 尝试调用 AFHTTPRequestOperation 中的失败块,而是应用程序“沙滩球”——我的应用程序中的其他文件进程继续运行,但 AFNetworking 陷入僵局——可能正在等待某种信号量。这是一个示例调用堆栈:
Thread 0x958 DispatchQueue 1 priority 47
31 ??? (My App + 4980) [0x106b5b374]
31 NSApplicationMain + 869 (AppKit) [0x7fff8630fc06]
31 -[NSApplication run] + 517 (AppKit) [0x7fff8636b1d3]
31 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128 (AppKit) [0x7fff86373e22]
31 _DPSNextEvent + 685 (AppKit) [0x7fff86374563]
31 BlockUntilNextEventMatchingListInMode + 62 (HIToolbox) [0x7fff90109ae3]
31 ReceiveNextEventCommon + 356 (HIToolbox) [0x7fff90109c52]
31 RunCurrentEventLoopInMode + 209 (HIToolbox) [0x7fff90109eb4]
31 CFRunLoopRunSpecific + 290 (CoreFoundation) [0x7fff8de710e2]
31 __CFRunLoopRun + 789 (CoreFoundation) [0x7fff8de717f5]
31 __CFRunLoopDoSources0 + 245 (CoreFoundation) [0x7fff8de4e455]
31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17 (CoreFoundation) [0x7fff8de4eb31]
31 _cfstream_shared_signalEventSync + 640 (CoreFoundation) [0x7fff8ded3e00]
31 _signalEventSync + 108 (CoreFoundation) [0x7fff8de9503c]
31 ??? (My App + 162305) [0x106b81a01]
31 CFWriteStreamWrite + 380 (CoreFoundation) [0x7fff8de6f56c]
31 boundPairWrite + 586 (CoreFoundation) [0x7fff8df3f7ea]
31 _CFStreamSignalEvent + 615 (CoreFoundation) [0x7fff8de94df7]
31 _cfstream_solo_signalEventSync + 100 (CoreFoundation) [0x7fff8de94fc4]
31 _signalEventSync + 108 (CoreFoundation) [0x7fff8de9503c]
31 ??? (My App + 162305) [0x106b81a01]
31 CFWriteStreamWrite + 380 (CoreFoundation) [0x7fff8de6f56c]
31 boundPairWrite + 149 (CoreFoundation) [0x7fff8df3f635]
31 __psynch_mutexwait + 10 (libsystem_kernel.dylib) [0x7fff8a758122]
*31 psynch_mtxcontinue + 0 (mach_kernel) [0xffffff80005b34e0]
注意:这只发生在某些机器上——运行 Mountain Lion——报告了 5% 的用户,但我们只能在一台特定的机器上完全重现和测试。更不用说问题可能需要几个小时才能自然显现。
还请注意:当用户将鼠标悬停在我的应用程序的菜单栏 NSStatusItem 上时,它通常向用户显示为一个旋转的沙滩球。
请注意,即使我传入特定的后备队列(对于成功和失败),似乎也会出现相同的问题 - 但仅在(至少一台)机器上。其他机器工作绝对正常。这是最近的一次崩溃,它在调用回退队列上的成功块时实际崩溃了——发生这种情况时它已经运行了 8 个多小时,并且在此之前成功调用了数百次成功块:
Crashed Thread: 10 Dispatch queue: com.myapp.put.success.queue
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008
VM Regions Near 0x8:
Thread 10 Crashed:: Dispatch queue: com.myapp.put.success.queue
0 libdispatch.dylib 0x00007fff89920e1c _dispatch_retain + 0
1 libdispatch.dylib 0x00007fff89923871 dispatch_source_cancel + 17
2 com.mydomain.myapp 0x0000000109154722 __PUTfiles_block_invoke281 + 98
3 com.mydomain.myapp 0x000000010916b32c __64-[AFJSONRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke79 + 44
4 libdispatch.dylib 0x00007fff89923f01 _dispatch_call_block_and_release + 15
5 libdispatch.dylib 0x00007fff899200b6 _dispatch_client_callout + 8
6 libdispatch.dylib 0x00007fff8992147f _dispatch_queue_drain + 235
7 libdispatch.dylib 0x00007fff899212f1 _dispatch_queue_invoke + 52
8 libdispatch.dylib 0x00007fff899211c3 _dispatch_worker_thread2 + 249
9 libsystem_c.dylib 0x00007fff8705cd0b _pthread_wqthread + 404
10 libsystem_c.dylib 0x00007fff870471d1 start_wqthread + 13
Thread 10 crashed with X86 Thread State (64-bit):
rax: 0x1c711b723ffeb051 rbx: 0x0000000000000000 rcx: 0x00007faa010eb040 rdx: 0x00000000a1a1a1a1
rdi: 0x0000000000000000 rsi: 0x00007faa010eb000 rbp: 0x000000010aa5ad20 rsp: 0x000000010aa5ad08
r8: 0x00007faa0287b970 r9: 0x0000000064cb29bf r10: 0x00007faa0289a570 r11: 0x000000006744ce88
r12: 0x0000000000010001 r13: 0x0000000000000000 r14: 0x00007faa01842540 r15: 0x00007faa01842574
rip: 0x00007fff89920e1c rfl: 0x0000000000010206 cr2: 0x0000000000000008
Logical CPU: 0
退出应用程序并重新启动它有助于重置。请注意,这只发生在 NSURLRequest 超时(60 秒)时 - 服务器实际响应的其他故障处理得很好并且不会发生挂起。该过程继续并再次正确尝试。
我目前正在尝试一个看门狗块,它在 PUT 开始后 45 秒被调用,如果尚未完成则取消操作。当我将其设置为 0.25 秒时,它在有问题的机器上运行良好 - 取消操作并重新开始尝试。我希望这可以解决问题,但是已经在这个用户机器上尝试了 2 周的这个错误(在构建后使用日志语句来尝试追踪事情)我没有屏住呼吸。请注意,因为在调用上面的成功块时它也崩溃了,我现在有点担心这甚至是正确的方法 - 成功崩溃是今天早上新出现的 - 它以前一直是失败崩溃。
想法?提前致谢!