NSManagedObjectContexts 和多线程

发布于 2024-10-04 04:37:01 字数 1594 浏览 3 评论 0原文

假设我们有一个应用程序需要显示地点列表,并且在 3 个线程上运行:

  1. 主线程
  2. 主线程 后台同步(用于同步 有服务器的地方)
  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:

  1. Main Thread
  2. Main Thread Background Sync (to sync
    places with a server)
  3. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

偏闹i 2024-10-11 04:37:01

我认为你的应用程序结构使你处于危险境地。在我看来,竞争条件是在您从存储字典中删除 MOC 之前,某些线程“A”消失了。因此,您尝试在线程“A”上向它发送消息,但它死了。

相反,可以这样想:

  • 每个线程都有一个线程本地对象,您可以将其存储在线程本地存储中(请参阅 NSThread 文档,查找 threadDictionary)。
  • 该对象是在线程开始执行其工作时创建的,并设置 MOC由给定线程使用
  • 该对象还注册保存通知,并在线程工作的生命周期内监视它们
  • 。在线程工作结束时,该对象被销毁。

通过这种方式,您可以封装托管对象上下文的生命周期,并将其直接绑定到引用它的通知机制。通过将监视器对象存储在线程本地存储中,您还将这两点与线程的生命周期联系起来。

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:

  • Each thread has a thread local object, that you can store inside the thread local storage (see NSThread docs, look for threadDictionary)
  • This object is created when your thread starts doing it's work, and sets up the MOC to be used by a given thread
  • The object also registers for save notifications, and monitors them for the lifetime of the threads work
  • At the end of the threads work this object is destroyed.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文