NSManagedObjectContexts 和多线程
假设我们有一个应用程序需要显示地点列表,并且在 3 个线程上运行:
- 主线程
- 主线程 后台同步(用于同步 有服务器的地方)
- 地理编码 线程(对位置进行地理编码 背景)
在所有 3 个线程中,我都有专用的 NSManagedObjectContexts(MOC)。如果每个 MOC 可以更改底层数据(例如,主线程可以将地点添加到您的收藏夹,而后台同步可以更改地点的名称,而地理编码线程添加 lat/lng 信息),则应用程序将必须注册 NSManagedObjectContextDidSaveNotification
在每个线程中,然后将 mergeChangesFromContextDidSaveNotification
传播到其他线程中相应的其他 MOC(如果保存了一个 MOC)(而不仅仅是将它们合并到主线程的 MOC 中),对吗? ?
因为现在我正在这样做,但感觉不对:(
我有一本字典,我用它来保存当前正在运行的线程及其 MOC。每当其中一个 MOC 弹出 NSManagedObjectContextDidSaveNotification
我循环遍历这个数组并将 mergeChangesFromContextDidSaveNotification
发送到所有其他 MOC/Thread。当然,我还向 NSThreadWillExitNotification
添加了一个观察者,以便我可以从该数组中删除 Thread/MOC。当其中一个线程耗尽时,字典的所有添加/删除操作都会被锁定。 这就是我现在有点陷入困境的地方。有时,当我
[moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:)
onThread:thread
withObject:notification
waitUntilDone:YES];
在循环 MOC/线程字典时调用时,我会收到以下异常:
[NSManagedObjectContext performSelector:onThread:withObject:waitUntilDone:modes:]: target thread exited while waiting for the perform
显然,这是由竞争条件引起的。在循环字典时(我只在提取其对象数组时锁定它),其中的线程之一退出,因此引用不再有效。但是,如果我将字典锁放在整个循环前面,则会出现死锁,因为
[moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:)
onThread:thread
withObject:notification
waitUntilDone:YES];
循环内的调用在某些情况下会永远持续(还不知道为什么),从而导致整个应用程序停止运行。 在这种情况下,使用 waitUntilDone:NO
进行调用是否安全?因为这似乎可以解决它。我只是不知道,如果我不小心用这个打开了潘多拉盒子......
问候,
塞巴斯蒂安
Let's say we have an app that needs to display a list of places and which runs on 3 Threads:
- Main Thread
- Main Thread Background Sync (to sync
places with a server) - Geocoding
thread (to geocode places in the
background)
In all 3 threads I have dedicated NSManagedObjectContexts
(MOCs). If each MOC can change the underlying data (main thread can e.g. add the place to your favorites, while background sync can change the place's name, while the geocoding thread adds lat/lng information), the app will have to register for the NSManagedObjectContextDidSaveNotification
in each thread and then spread the mergeChangesFromContextDidSaveNotification
to the corresponding other MOCs in the other threads if one MOC gets saved (not just merge them into the main thread's MOC), right???
Cause right now I am doing that and it doesn't feel right :(
I have a dictionary, which I use to save the currently running threads with their MOCs. Whenever one of the MOCs pops the NSManagedObjectContextDidSaveNotification
I loop through this array and send the mergeChangesFromContextDidSaveNotification
to all other MOCs/Threads. Of course, I also added an observer to the NSThreadWillExitNotification
so that I can remove Thread/MOC from the array when one of the threads runs out. All add/remove actions for the dictionary are locked.
And that's where I am kinda stuck right now. Sometimes, when I call
[moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:)
onThread:thread
withObject:notification
waitUntilDone:YES];
when looping through the MOCs/thread dictionary, I get the following exception thrown at me:
[NSManagedObjectContext performSelector:onThread:withObject:waitUntilDone:modes:]: target thread exited while waiting for the perform
Apparently, this is caused by a race condition. While looping through the dictionary (I only locked it while extracting its objects array), one of the threads within exits and thus the reference is not valid anymore. However, if I put the dictionary lock in front of the entire loop, I get a deadlock, because the call
[moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:)
onThread:thread
withObject:notification
waitUntilDone:YES];
within the loop takes forever in some cases (don't know why yet) and thus causes the entire app to stall.
Is it safe to do the call with waitUntilDone:NO
in this case? Because that seems to fix it. I just don't know, if I accidentally open pandora's box with this....
Regards,
Sebastian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为你的应用程序结构使你处于危险境地。在我看来,竞争条件是在您从存储字典中删除 MOC 之前,某些线程“A”消失了。因此,您尝试在线程“A”上向它发送消息,但它死了。
相反,可以这样想:
通过这种方式,您可以封装托管对象上下文的生命周期,并将其直接绑定到引用它的通知机制。通过将监视器对象存储在线程本地存储中,您还将这两点与线程的生命周期联系起来。
I think your application structure is putting you in a hazardous situation. It sounds to me like the race condition is that some Thread "A" goes away before you remove the MOC from your storage dictionary. Thus you try to send it a message on Thread "A" and it dies.
Instead think of it this way:
This way you encapsulate the life-cycle of the managed object context and directly tie it to the notification mechanism that will reference it. By storing the monitor object in the thread local storage you also tie those two points of concern to the lifetime of the thread.