首页 / 知识

关于可可:如果我没有在创建线程的线程上显式访问它们,是否可以安全地操作在线程之外创建的对象?

2023-04-15 14:50:00

关于可可:如果我没有在创建线程的线程上显式访问它们,是否可以安全地操作在线程之外创建的对象?

Is it safe to manipulate objects that I created outside my thread if I don't explicitly access them on the thread which created them?

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

即使我在线程运行时没有显式访问那些对象,即使我在主线程中创建了这些对象而不使用锁也可以安全地访问这些对象。


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

没有免费的午餐。

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

对于核心数据中的线程之间共享数据(如之前的Enterprise Objects Framework)的解决方案是"不要"。如果您进一步考虑了这一点,并且确实需要在线程之间共享数据,那么解决方案是将独立的对象图保留在线程隔离的上下文中,并使用来自一个上下文的save通知中的信息来告知线程其他上下文要重新获取的内容。 -[NSManagedObjectContext refreshObject:mergeChanges:]是专门为支持此用途而设计的。


我相信这对由CoreData NSManagedObjectContext管理的NSManagedObjects(或子类)是不安全的。通常,CoreData可能会对托管对象进行很多棘手的事情,包括在单独的线程中引发与那些对象有关的故障。特别是[NSManagedObject initWithEntity:insertIntoManagedObjectContext:](从OS X 10.5开始为NSManagedObjects指定的初始化程序)不能保证返回的对象可以安全地传递到另一个线程。

在Apple的开发站点上可以很好地证明将CoreData与多个线程一起使用。


要考虑的两件事是:

  • 您必须能够保证对象已完全创建和初始化,然后才可用于其他线程。
  • 主(GUI)线程必须通过某种机制来检测数据已加载并且一切正常。为了线程安全,这将不可避免地涉及某种形式的锁定。

是的,您可以做到,这将是安全的

...
直到第二位程序员出现并且不了解您所做的相同假设。第二个(或第3个,第4个,第5个……)程序员可能会以一种不安全的方式(在创建者线程中)开始使用该对象。造成的问题可能非常微妙,难以追踪。仅出于这个原因,并且因为它很想在多个线程中使用该对象,所以我将使对象线程安全。

为了澄清,(感谢那些发表评论的人):

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

例如,在C ++中

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

然后,在创建线程中,您将无法在创建对象后再访问该对象,将责任转移给使用线程。


是的,很安全。一个很常见的模式是创建一个对象,然后将其添加到队列或其他集合中。第二个"消费者"线程从队列中取出项目并对其进行处理。在这里,您需要同步队列,而不是添加到队列的对象。

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


即使是安全的,但在线程之间使用共享数据而不同步对这些字段的访问也不是最佳实践。哪个线程创建对象无关紧要,但是是否有多个执行行(线程/进程)同时访问该对象,因为这可能导致数据不一致。

如果您完全确定只有一个线程将访问此对象,那么不同步访问将是安全的。即使那样,我还是希望现在就在代码中进行同步,而不是等到以后应用程序中的更改使第二个线程共享同一数据而不必担心同步访问时再进行同步。


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


线程对象操作显式

最新内容

相关内容

猜你喜欢