代码之家  ›  专栏  ›  技术社区  ›  Community wiki

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

  •  3
  • Community wiki  · 技术社区  · 1 年前

    我正在开发一个可可软件,为了在大规模数据导入(核心数据)过程中保持GUI的响应,我需要在主线程之外运行导入。

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

    7 回复  |  直到 1 年前
        1
  •  4
  •   Chris Hanson    16 年前

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

    没有免费的午餐。

    Ben Trumbull解释了为什么你需要使用单独的上下文,以及为什么“仅仅阅读”并不像你想象的那么简单或安全 this great post from late 2004 on the webobjects-dev list 。(整个线程都很棒。)他正在讨论企业对象框架和WebObjects,但他的建议也完全适用于核心数据。只需在他的信息中用“NSManagedObjectContext”替换“EC”,用“核心数据”替换“EOF”。

    核心数据中线程之间共享数据的问题的解决方案是“不要”,就像之前的企业对象框架一样,并且使用来自一个上下文的保存通知中的信息来告诉另一个上下文要重新获取什么。 -[NSManagedObjectContext refreshObject:mergeChanges:] 是专门为支持这种用途而设计的。

        2
  •  1
  •   Barry Wark    16 年前

    我相信这是 使用由CoreData NSManagedObjectContext管理的NSManagedObjects(或子类)是安全的。通常,CoreData可能会对托管对象的状态做许多棘手的事情,包括在单独的线程中触发与这些对象相关的故障。特别地, [NSManagedObject initWithEntity:insertIntoManagedObjectContext:] (从OS X 10.5起,NSManagedObjects的指定初始值设定项)不能保证返回的对象可以安全地传递给其他线程。

    在Apple的 dev site

        3
  •  0
  •   Mark Ransom    16 年前

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

        4
  •  0
  •   Alexandre Brasil    16 年前

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

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

        5
  •  0
  •   Tim Frey    16 年前

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

    仅仅同步所有内容并抱着最好的希望不是一个好主意。你需要非常仔细地考虑你的设计,以及哪些线程可以作用在你的对象上。

        6
  •  0
  •   Garth Gilmour    16 年前

    需要考虑的两件事是:

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

    是的,你能做到,它会很安全

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

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

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

    例如,在C中++

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

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