2

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

  1. 主线程
  2. 主线程后台同步(与服务器同步位置)
  3. 地理编码线程(在后台对地点进行地理编码)

在所有 3 个线程中,我都有专用的NSManagedObjectContexts(MOC)。如果每个 MOC 都可以更改底层数据(例如,主线程可以将地点添加到您的收藏夹,而后台同步可以更改地点的名称,而地理编码线程添加纬度/经度信息),应用程序将必须NSManagedObjectContextDidSaveNotification在每个mergeChangesFromContextDidSaveNotification如果一个 MOC 被保存(而不仅仅是将它们合并到主线程的 MOC 中),则将其传播到其他线程中相应的其他 MOC,对吗???

因为现在我正在这样做,但感觉不对:(

我有一本字典,我用它来保存当前正在运行的线程及其 MOC。每当其中一个 MOC 弹出时,NSManagedObjectContextDidSaveNotificationI 循环通过该数组并将其发送mergeChangesFromContextDidSaveNotification到所有其他 MOC/线程。当然,我还添加了一个观察者,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在这种情况下打电话安全吗?因为这似乎可以解决它。我只是不知道,如果我不小心用这个打开了潘多拉的盒子......

问候,

塞巴斯蒂安

4

1 回答 1

1

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

而是这样想:

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

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

于 2010-11-23T23:14:54.923 回答