我们的应用似乎是半随机挂在psynch_mutexwait。 它似乎与更新存储在CoreData中的大量数据的后台进程有关 - 但我完全无法弄清楚是谁锁定导致死锁的原因。
以下是lldb给我的完整堆栈跟踪 - 这显然是不完整的,并且线程1的最后一帧是伪造的。
之前,我在该方法中有一个断点,在此之前几行有没有办法搞清楚等待什么锁? (或者甚至获得正确的堆栈跟踪?)当然,涉及很多代码,这使随机的NSLog语句成为一项艰巨的任务。
(lldb) bt all
* thread #1: tid = 0x2503, 0x39da20fc libsystem_kernel.dylib`__psynch_mutexwait + 24, stop reason = signal SIGSTOP
frame #0: 0x39da20fc libsystem_kernel.dylib`__psynch_mutexwait + 24
frame #1: 0x39ceb128 libsystem_c.dylib`pthread_mutex_lock + 392
frame #2: 0x00022068 OnDeck`-[AttendanceWorkoutsController buildTable](self=0x00000003, _cmd=0x00000000) + 508 at AttendanceWorkoutsController.m:100
thread #2: tid = 0x2803, 0x39d92648 libsystem_kernel.dylib`kevent64 + 24
frame #0: 0x39d92648 libsystem_kernel.dylib`kevent64 + 24
frame #1: 0x39ccb4f0 libdispatch.dylib`_dispatch_mgr_invoke + 796
thread #5: tid = 0x2b03, 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #0: 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #1: 0x39d9204c libsystem_kernel.dylib`mach_msg + 40
thread #6: tid = 0x242f, 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #0: 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #1: 0x39d9204c libsystem_kernel.dylib`mach_msg + 40
thread #7: tid = 0x2c03, 0x39da2594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20
frame #0: 0x39da2594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20
frame #1: 0x31bff1f6 CoreFoundation`__CFSocketManager + 678
thread #8: tid = 0x2d03, 0x39da2d98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #0: 0x39da2d98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #1: 0x39cf0cfa libsystem_c.dylib`_pthread_workq_return + 18
(lldb)
答案 0 :(得分:13)
通过让几个人查看代码,并追踪冗长复杂的代码路径,我们发现了似乎是罪魁祸首。 在后台线程中运行的一种方法是查找并使用一些Core Data对象并使用主线程上下文。
如果IOS能提供有用的堆栈跟踪,肯定会帮助很多。
答案 1 :(得分:2)
当另一个上下文(以及另一个线程)中的相关实体已被修改但尚未保留时,就会发现这种情况。
情景:
A --> B
由于某个错误B
有未决更改,在另一个上下文中,在另一个线程上。该Bug导致B
挂起而不是保存或回滚。
试图在当前上下文/线程中保存A
将导致等待另一个线程释放B
上的锁。
只有成功解决问题的方法是列出所有待处理实体并与阻止线程中的实体进行比较。花了一段时间:(
我仍在寻找列出数据库和实体上所有锁的内容。
答案 2 :(得分:2)
当使用主线程上下文 OR 同时在不同线程(背景或主要)上使用相同的托管对象上下文尝试访问后台线程上的Core Data对象时,通常会发生这种情况。有关详细信息,请查看Core Data concurrency rules。
因此,为了避免这两种情况,主要规则是,每个线程必须有自己的托管对象上下文,并准确地初始化该上下文。
例如:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//
// Prepare your background core data context
//
if (self.privateContext == nil)
{
self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[self.privateContext setParentContext: - main managed object context - ];
[self.privateContext setUndoManager:nil]; // this context should not manage undo actions.
}
//
// Do any Core Data requests using this thread-save context
//
.
.
.
});