waitUntilAllOperationsAreFinished和objectWithID

时间:2014-12-20 22:12:57

标签: objective-c core-data swift nsoperationqueue

更新我可以确认objectWithID可能需要父(或祖父母等)上下文的线程来进行一些提取,因此请避免使用{{1}之类的内容阻止您的父线程}。

作为一个快速测试,我将孩子moc的父母指向了他们的祖父母,并让孩子的线程阻挡了原来的父母。在此设置中,永远不会发生死锁。这是一个糟糕的架构,所以我将重新架构。

原始问题

我有两层waitUntilAllOperationsAreFinished。第一个是NSOperationQueue图形,其操作在它们之间具有一组依赖关系。他们都运行良好,没有相互僵局。在其中一个操作(一组人员的调度程序)中,我将其工作分解为可以在另一个NSOperation上运行的更多离散块。但是,我仍然希望Scheduler在考虑完成较大的操作之前完成所有的日程安排。为此,一旦我创建了所有Schedule操作并将它们添加到Scheduler操作队列,我就在操作队列上调用waitUntilAllOperationsAreFinished。这就是我陷入僵局的地方。

我正在使用Core Data并且有一个名为NSOperationQueue的{​​{1}}子类,它处理获取父管理对象上下文的例程,创建PrivateQueueConcurrencyType子上下文,使用performBlockAndWait调用提供的块,最后等待在父上下文中合并更改。这是一些代码......

NSBlockOperation

这对我来说非常有用。但现在我想阻塞一个调用线程,直到它上面的操作队列完成所有操作。像这样......

BlockOperation

...这个帖子卡在最后一行(显然)。但我们从未看到其他线程在某一点上取得任何进展。暂停调试器我看到排队操作卡在哪里。它位于ScheduleOperation的init方法中,我们使用提供的id获取组。 (ScheduleOperation.scheduleGroupId调用此init)

init(block: (NSManagedObjectContext?) -> Void, withDependencies dependencies: Array<NSOperation>, andParentManagedObjectContext parentManagedObjectContext: NSManagedObjectContext?) {
    self.privateContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)

    super.init()

    self.queuePriority = NSOperationQueuePriority.Normal
    addExecutionBlock({
        if (parentManagedObjectContext != nil) {
            self.parentContext = parentManagedObjectContext!

            self.privateContext.parentContext = parentManagedObjectContext!

            self.privateContext.performBlockAndWait({ () -> Void in
                block(self.privateContext)
            })

            self.parentContext!.performBlockAndWait({ () -> Void in
                var error: NSError?
                self.parentContext!.save(&error)
            })
        }
    })

    for operation in dependencies {
        addDependency(operation)
    }
}

objectWithID是否需要在与其父moc关联的“父”线程上执行代码,从而产生死锁?我的方法还有什么可能导致这种情况吗?

注意:虽然我写的是Swift,但我已经将Objective-C添加为标记,因为我觉得这不是特定于语言的问题,而是特定于框架的问题。

1 个答案:

答案 0 :(得分:1)

一般情况下,没有指定将调用哪个线程objectWithID,这是一个实现细节。我在过去遇到了一些Core Data死锁的问题(虽然在不同的情况下),我发现当你在NSManagedObjectContext上调用方法时,框架会在内部进行一些锁定。所以,是的,我认为这可能会导致僵局。

除了重新设计您的架构之外,我没有任何建议,也许它可以简化一点。请记住,您已经有一个与上下文关联的专用串行队列,这可以保证以指定的顺序调用操作。因此,您可以在所有ScheduleOperation实例之间共享相同的上下文。将scheduleOperationQueue.maxConcurrentOperationsCount设置为1,以便操作将一个接一个地执行。而不是阻塞调用线程,在最后一个操作完成时调用完成处理程序(您可以使用oepration的completionBlock)。