Objective c 保存托管对象上下文会在iOS 5的performBlock中创建死锁

Objective c 保存托管对象上下文会在iOS 5的performBlock中创建死锁,objective-c,ios,core-data,deadlock,nsmanagedobjectcontext,Objective C,Ios,Core Data,Deadlock,Nsmanagedobjectcontext,我一直在寻找解决这个问题的方法很长时间了,现在还没有找到 我正在开发一款具有核心数据的iOS应用程序。我已经创建了两个托管对象上下文MOC,它们指向同一个持久存储协调器。一个称为self.MOC的MOC是通过主队列并发启动的,而另一个称为self.bmoc的mov是通过专用队列并发启动的。我已确保self.moc仅在主线程上运行,self.bmoc仅在其performBlock或performBlockAndWait块内运行 然而,我遇到了这种奇怪的情况,我的应用程序在[self.bmoc sa

我一直在寻找解决这个问题的方法很长时间了,现在还没有找到

我正在开发一款具有核心数据的iOS应用程序。我已经创建了两个托管对象上下文MOC,它们指向同一个持久存储协调器。一个称为self.MOC的MOC是通过主队列并发启动的,而另一个称为self.bmoc的mov是通过专用队列并发启动的。我已确保self.moc仅在主线程上运行,self.bmoc仅在其performBlock或performBlockAndWait块内运行

然而,我遇到了这种奇怪的情况,我的应用程序在[self.bmoc save:nil]行冻结。由于save操作是在performBlock块中执行的,因此我不认为它会出现死锁。由于该行冻结,因此即使使用[self.bmoc save:&error]而不是nil,我也无法接收错误

下面是重现问题的代码。虽然我有许多类似于下面的函数,但只有这一个会产生问题。我无法找出问题的原因,我们非常感谢您的任何见解。谢谢大家!

-(void)createEmptyUserData {
    [self.bmoc performBlock:^{
        User* user = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.bmoc];
        /* sets user object */
        [self.bmoc save:nil];
    }];
}

注意:这段代码是在主线程中执行的。

在这种情况下,有两个基本原因会导致挂起

您有一个对performBlockAndWait的嵌套调用或其他一些同步线程/队列调用

你的一个街区不会回来,永远在跑

通过查看挂起时每个运行线程的堆栈,可以很容易地看到这两种情况

performBlock只需获取执行块并将其添加到队列中,然后立即返回。然后,其他一些线程从队列中弹出执行块并执行它们

performBlockAndWait在调用线程的上下文中执行。基本上,它会等待当前排队的执行块运行,然后在当前线程上运行请求的代码

在调用完成之前,它不会返回

所以,我敢打赌,要么有多个嵌套调用执行performBlockAndWait,要么一个异步执行块没有完成

看看挂起时的堆栈


或者,记录块的执行情况,以便查看每个块何时开始和退出。

在这种情况下,有两个基本原因会导致挂起

您有一个对performBlockAndWait的嵌套调用或其他一些同步线程/队列调用

你的一个街区不会回来,永远在跑

通过查看挂起时每个运行线程的堆栈,可以很容易地看到这两种情况

performBlock只需获取执行块并将其添加到队列中,然后立即返回。然后,其他一些线程从队列中弹出执行块并执行它们

performBlockAndWait在调用线程的上下文中执行。基本上,它会等待当前排队的执行块运行,然后在当前线程上运行请求的代码

在调用完成之前,它不会返回

所以,我敢打赌,要么有多个嵌套调用执行performBlockAndWait,要么一个异步执行块没有完成

看看挂起时的堆栈


或者,记录块的执行情况,以便查看每个块何时启动和退出。

是否了解死锁发生的位置?任何ValidateMething方法或willSave方法是否锁定了某些内容?死锁意味着两个线程互相等待,另一个线程在哪里等待?谢谢你的回复。执行完这段代码后,主线程继续运行,并在[self.bmoc performBlockAndWait^{}结束,在此等待上面的代码完成执行,导致主线程冻结。我不知道是否有任何ValidateMething方法或willSave方法。您可以尝试添加-com.apple.CoreData.SQLDebug 3以启用调试,并查看是否有任何内容实际被保存。此外,可能此块实际上正在等待前一个块完成,而该块被卡住了?上下文是嵌套的还是共享上下文相同的持久性t存储协调器?了解死锁发生的位置吗?任何ValidateMething方法或willSave方法是否锁定了某些内容?死锁意味着两个线程互相等待,另一个线程在哪里等待?谢谢你的回复。执行完这段代码后,主线程继续运行,并在[self.bmoc performBlockAndWait^{}结束,在此等待上面的代码完成执行,导致主线程冻结。我不知道是否有任何ValidateMething方法或willSave方法。您可以尝试添加-com.apple.CoreData.SQLDebug 3以启用调试,并查看是否有任何内容实际被保存。此外,可能此块实际上正在等待前一个块完成,而这就是被卡住的块?上下文是嵌套的还是正确的
这与fabrice truillot de chambrier所说的类似。我将深入研究您提供的方向的问题,稍后再与您联系。谢谢你,谢谢你引导我找到答案。稍后我将编辑此内容,并提供一些有关问题原因和解决方法的详细信息。我认为我可以编辑评论,但显然我错了。无论如何,问题的原因是[self.bmoc save:nil];调用contextDidChange:保存过程完成后。在我的contextDidChange:,我有[self.moc performBlockAndWait^{//mergeContext}]。正如我在我的问题下的评论中提到的,我的主线程继续运行,并在[self.bmoc performBlockAndWait^{}结束。问题应该很清楚:两个队列都在等待对方完成,从而导致死锁。我的解决方案是在contextDidChange:中将performBlockAndWait更改为锁定和解锁。contextDidChange:是您的通知处理程序吗?我喜欢打电话给[self.moc performBlock^{/*随便什么*/}];过度显式锁定。是的。由于[self.moc performBlock^{/*which*/}导致死锁,我想我必须使用显式锁。这与fabrice truillot de chambrier所说的类似。我将深入研究您提供的方向的问题,稍后再与您联系。谢谢你,谢谢你引导我找到答案。稍后我将编辑此内容,并提供一些有关问题原因和解决方法的详细信息。我认为我可以编辑评论,但显然我错了。无论如何,问题的原因是[self.bmoc save:nil];调用contextDidChange:保存过程完成后。在我的contextDidChange:,我有[self.moc performBlockAndWait^{//mergeContext}]。正如我在我的问题下的评论中提到的,我的主线程继续运行,并在[self.bmoc performBlockAndWait^{}结束。问题应该很清楚:两个队列都在等待对方完成,从而导致死锁。我的解决方案是在contextDidChange:中将performBlockAndWait更改为锁定和解锁。contextDidChange:是您的通知处理程序吗?我喜欢打电话给[self.moc performBlock^{/*随便什么*/}];过度显式锁定。是的。由于[self.moc performBlock^{/*which*/}]导致死锁,我想我必须使用显式锁。