如果我不在创建对象的线程上显式访问它们,那么操作在线程外部创建的对象是否安全?

StackOverflow https://stackoverflow.com/questions/67154

我正在开发一个 cocoa 软件,为了在大量数据导入(核心数据)期间保持 GUI 响应,我需要在主线程之外运行导入。

即使我在主线程中创建了这些对象而不使用锁,访问这些对象是否安全 如果 在线程运行时我不会显式访问这些对象。

有帮助吗?

解决方案

使用 Core Data,您应该有一个单独的托管对象上下文用于导入线程,连接到相同的协调器和持久存储。您不能简单地将在主线程使用的上下文中创建的对象扔到另一个线程中并期望它们工作。此外,您不能为此进行自己的锁定;您必须至少根据需要锁定对象所在的托管对象上下文。但是,如果这些对象由您的视图和控件绑定到,则没有可以添加上下文锁定的“钩子”。

天下没有免费的午餐。

Ben Trumbull 解释了为什么您需要使用单独的上下文的一些原因,以及为什么“只是阅读”并不像您想象的那么简单或安全,在 webobjects-dev 列表中 2004 年底发表的这篇很棒的文章. 。(整个线程很棒。)他正在讨论企业对象框架和 WebObjects,但他的建议也完全适用于 Core Data。只需将消息正文中的“EC”替换为“NSManagedObjectContext”,将“EOF”替换为“Core Data”即可。

解决核心数据中线程之间共享数据的问题(例如企业对象框架之前)是“不要”。如果您您进一步考虑了它,那么您确实必须在线程之间共享数据,那么解决方案是将独立的对象图保持在线程隔离的上下文中,并使用从一个上下文中的保存通知中使用信息来告诉其他上下文重新提取的内容。 -[NSManagedObjectContext refreshObject:mergeChanges:] 是专门为支持这种用途而设计的。

其他提示

我相信这是 不是 可以安全地处理由 CoreData NSManagedObjectContext 管理的 NSManagedObjects(或子类)。一般来说,CoreData 可能会对托管对象的状态执行许多棘手的操作,包括在单独的线程中触发与这些对象相关的错误。尤其, [NSManagedObject initWithEntity:insertIntoManagedObjectContext:] (从 OS X 10.5 开始,NSManagedObjects 的指定初始值设定项)不保证返回的对象可以安全地传递给其他线程。

在 Apple 的文档中详细记录了将 CoreData 与多个线程一起使用 开发站点.

使用锁的全部目的是确保两个线程不会尝试访问同一资源。如果你能通过其他机制保证这一点,那就去做吧。

即使它是安全的,但在线程之间使用共享数据而不同步对这些字段的访问也不是最佳实践。哪个线程创建该对象并不重要,但如果多个执行行(线程/进程)同时访问该对象,则可能会导致数据不一致。

如果您绝对确定只有一个线程会访问该对象,那么不同步访问是安全的。即便如此,我宁愿现在就将同步放入我的代码中,而不是等到应用程序中的更改使第二个线程共享相同的数据而不用担心同步访问时。

是的,很安全。一种非常常见的模式是创建一个对象,然后将其添加到队列或其他集合中。第二个“消费者”线程从队列中获取项目并对其执行某些操作。在这里,您需要同步队列,但不需要同步添加到队列中的对象。

仅仅同步所有内容并希望得到最好的结果并不是一个好主意。您需要非常仔细地考虑您的设计以及哪些线程可以作用于您的对象。

需要考虑的两件事是:

  • 您必须能够保证该对象在可供其他线程使用之前已完全创建和初始化。
  • 必须有某种机制可以让主(GUI)线程检测到数据已加载且一切正常。为了线程安全,这将不可避免地涉及某种类型的锁定。

是的,你可以做到,而且很安全

...直到第二个程序员出现并且不理解您所做的相同假设。第二个(或第三、第四、第五……)程序员可能会开始以非安全方式(在创建者线程中)使用该对象。造成的问题可能非常微妙且难以追踪。仅出于这个原因,并且由于在多个线程中使用此对象非常诱人,我将使该对象成为线程安全的。

澄清一下,(感谢那些留下评论的人):

我所说的“线程安全”是指以编程方式设计一个方案来避免线程问题。我并不一定意味着围绕你的对象设计一个锁定方案。您可以在您的语言中找到一种方法,使在创建者线程中使用该对象变得非法(或非常困难)。例如,在创建者线程中将范围限制为创建对象的代码块。创建后,将对象传递给用户线程,确保创建者线程不再拥有对其的引用。

例如,在 C++ 中

void CreateObject()
{
    Object* sharedObj = new Object();
    PassObjectToUsingThread( sharedObj); // this function would be system dependent
}

然后,在您的创建线程中,您在创建对象后不再有权访问该对象,责任将传递给使用线程。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top