How does this cause deadlock (once in a while) and how do I unravel this

佐手、 提交于 2019-12-02 19:34:36

问题


@synchronized (self.class)     {
    fetchedObjects = [moc executeFetchRequest:request error:&error];
}

moc is a managedObjectContext

It can be the moc that correspond to the main thread. That moc is the parent of all MOC.

The other moc are just children. Sometimes when the child do executeFetchRequest it will also make the parent moc do the same executeFetchRequest.

What I often see is

outside main thread:

@synchronized (self.class)     {
    fetchedObjects = [moc executeFetchRequest:request error:&error]; //semaphore_wait_trap here
}

On main thread

@synchronized (self.class)     {//_psynch_mutexwait
    fetchedObjects = [moc executeFetchRequest:request error:&error];
}

Okay... Why the deadlock? Even though the moc on main thread correspond to the main thread it's not being accessed at all. It wait at @synchronized. So why fetchedObjects = [moc executeFetchRequest:request error:&error]; wait?


回答1:


You shouldn't be @synchronize-ing calls to executeFetchRequest:

The executeFetchRequest:error: method intrinsically scales its behavior appropriately for the hardware and work load. If necessary, the Core Data will create additional private threads to optimize fetching performance. You will not improve absolute fetching speed by creating background threads for the purpose. It may still be appropriate, however, to fetch in a background thread or queue to prevent your application’s user interface from blocking. This means that if a fetch is complicated or returns a large amount of data, you can return control to the user and display results as they arrive.

Core Data Programming Guide: Concurrency

Basically if you're returning a lot of objects and processing them, it's best to do that from a private queue context (since you can then use the returned objects on that private queue and process them off the main queue).

If you have a main queue context, only use it from the main queue.

Also, child contexts execute fetch requests by passing them to their parents. What happens (from what I can tell) is that the predicate gets evaluated on the persistent store (SQL), and on the unsaved objects in each MOC in the chain. This means that if you, say, override a getter that is used in a predicate, it will be called on those unsaved objects in memory (whereas the SQL predicate uses the raw DB values to compare against). You can deadlock a parent context by blocking its queue from a child context.




回答2:


The moc is holding its own lock so you have a lock in a lock -- now when t1 comes, he gets lock 1 but maybe not lock because somebody is fetching already and has lock2 but that one is blocked by t1 (which is waiting)



来源:https://stackoverflow.com/questions/14335640/how-does-this-cause-deadlock-once-in-a-while-and-how-do-i-unravel-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!