12

我们的应用程序似乎半随机地挂在 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) 
4

3 回答 3

13

通过让几个人查看代码,并追踪冗长复杂的代码路径,我们发现了似乎是罪魁祸首。在后台线程中运行的一种方法是查找和使用一些 Core Data 对象并使用主线程上下文。

如果 IOS 会提供有用的堆栈跟踪,肯定会有很大帮助。

于 2013-08-22T23:02:10.427 回答
2

This has seen when a related entity in another context (and on another thread) has been modified but not yet persisted.

The scenario:

A --> B

Due to a bug B had pending changes, in another context, on another thread. The Bug caused B to hang around instead of saving or rolling it back. Attempting to save A in the current context/thread will will cause the wait for the other thread to release the lock on B.

Only successful way to trouble shoot was to list all pending entities and compare to ones in the blocked thread. Took a while :(

I am still looking for something that list all locks on the database and entities.

于 2013-08-21T06:07:52.240 回答
2

这通常发生在尝试使用主线程上下文访问后台线程上的核心数据对象同时在不同线程(后台或主线程)上使用相同的托管对象上下文时。有关更多详细信息,请查看Core Data 并发规则

因此,为了避免这两种情况,主要规则是,每个线程必须有自己的托管对象上下文,并在将要使用的位置准确地初始化该上下文。

例如:

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
   //

   .
   .
   .

});
于 2015-12-06T01:35:38.757 回答