从主队列调用 dispatch_sync 并且执行的块保存到核心数据时 iOS 死锁

Posted

技术标签:

【中文标题】从主队列调用 dispatch_sync 并且执行的块保存到核心数据时 iOS 死锁【英文标题】:iOS deadlocks when calling dispatch_sync from main queue and the executed block saves to Core data 【发布时间】:2014-03-09 14:38:16 【问题描述】:

我有一个使用父上下文的核心数据实现。 我有一个在主队列上运行的主上下文和一个在私有队列上运行的后台上下文,主上下文是他的父级。

我使用以下内容覆盖上下文保存方法:

- (BOOL)save:(NSError **)error 
  BOOL retVal = YES;

  if (self.parentContext) 
    //push changes to parent context.
    retVal = [super save:error];

    if (retVal) 
      //save parent context.
      [self.parentContext performBlock:^
        [self.parentContext save:error];
      ];
    
   else 
    //save changes.
    retVal = [super save:error];
  

  return retVal;

我的问题是当我的主队列调用时:

- (BOOL)doSomething 
  __block BOOL retVal;

  dispatch_sync(workerQueue, ^
    retVal = [super doSomething];
  );

  return retVal;

如果[super doSomething] 调用了上下文保存方法,我会遇到死锁(死锁在我的保存方法中:retVal = [super save:error];)。

这是工作队列的堆栈跟踪:

0 semaphore_wait_trap
1_dispatch_thread_semaphore_wait$VARIANT$mp
2_dispatch_barrier_sync_f_slow
3_perform 
4-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error]
5 -[NSManagedObjectContext save:]

这是主队列的堆栈跟踪:

0 semaphore_wait_trap 
1 _dispatch_thread_semaphore_wait$VARIANT$mp 
2 _dispatch_barrier_sync_f_slow 
3 [Service doSomething]

出于某种奇怪的原因,这只发生在 iPad 而不是 iPhone 上

有没有办法使用递归锁来克服这种死锁?

【问题讨论】:

“出于某种奇怪的原因,这只发生在 iPad 而不是 iPhone” 【参考方案1】:

您不得将自己的调度队列用于 Core Data 操作。使用performBlock:performBlockAndWait: 确保操作在队列上执行 与托管对象上下文相关联。

请参阅NSManagedObjectContext Class Reference 中的“并发”。

【讨论】:

以上是关于从主队列调用 dispatch_sync 并且执行的块保存到核心数据时 iOS 死锁的主要内容,如果未能解决你的问题,请参考以下文章

主队列中添加的同步操作(dispatch_sync)永远不会被执行,会死锁原因

为啥我们不能在当前队列上使用 dispatch_sync?

dispatch_sync()

Dispatch Queues调度队列

说说GCD中的死锁

主队列上的 dispatch_sync 与 dispatch_async