NSLock 实例应该是“全局的”吗?
Posted
技术标签:
【中文标题】NSLock 实例应该是“全局的”吗?【英文标题】:Should an NSLock instance be "global"? 【发布时间】:2009-10-17 16:21:30 【问题描述】:我应该在应用程序委托中创建一个NSLock
实例,供所有类使用吗?还是建议让每个类根据需要实例化自己的NSLock
实例?
例如,如果我可以访问跨两个视图控制器分布的托管对象上下文,那么锁定在第二种情况下是否有效?
【问题讨论】:
在使用手密码锁时非常害怕,并怀疑对它们的需要。 我不确定这意味着什么。如果使用线程,核心数据指南建议锁定对托管对象上下文的访问。除了手动编码的NSLock
lock-unlock 对,我还能用什么?
是的,我只是说,小心……在那种情况下是合适的。
【参考方案1】:
如果多个对象访问您的对象只是为了读取其内容,那么您根本不需要锁。如果至少有一个对象访问您的对象以写入/更新其内容,那么其他对象是否访问您的对象以读取或写入/更新它并不重要:在这种情况下,您需要一个锁。
现在,为了正确保护您的对象(在代码的关键部分,多个对象可以访问它),您必须使用 SAME LOCK INSTANCE,然后必须由所有可能访问您所在对象的对象共享愿意保护。
如果您的应用程序需要保护一个可以被大多数类同时访问的对象,那么拥有一个锁实例就可以了。如果您想要更好的性能(特别是如果同时访问您的对象的数量很高),那么您可以拥有多个锁。每个锁将负责允许/拒绝访问对象的特定属性/字段。这样,多个对象可以访问您的对象同时更改不同的属性/字段。您基本上是在增加对象上的并发操作数。但是,每个锁仍必须在将访问您正在保护的对象的其他对象之间共享。
为每个控制器设置一个锁实例根本行不通;这不会保护您的对象免受来自不同线程中其他对象的并发访问。 NSLock 是使用 POSIX pthread 互斥锁实现的,因此必须以完全相同的方式使用它。这在 NSLock 文档中也有明确说明:
警告:NSLock 类使用 POSIX 线程来实现其锁定行为。向 NSLock 对象发送解锁消息时,您必须确保该消息是从发送初始锁定消息的同一线程发送的。从不同的线程解锁锁可能会导致未定义的行为。
因此,为了保留临界区语义,获得锁的同一线程负责在完成时释放它。另请注意,锁定机制仅适用于快速操作,即您应该在释放之前仅在短时间内获取锁定。如果您需要等待不可预测的时间量,那么您需要一种不同的同步机制,即可以通过 NSCondition 类获得的条件变量。
希望这会有所帮助。
【讨论】:
从文档中可以清楚地看出,用于锁定特定线程的同一锁也将用于解锁。但是,从NSLock
的文档中不清楚是否必须在所有类中使用相同的锁实例。我还在阅读,如果我在发出相应的[myLock unlock]
之前多次使用[myLock lock]
,那么线程将冻结。所以我仍然不确定是否需要将myLock
的实例化和范围限制为被调用的特定类/线程,或者我是否可以毫无问题地使用应用程序范围的myLock
。
我建议阅读有关 posix pthread 互斥锁的文档。您将看到必须在所有将访问您要保护的对象的线程之间共享一个互斥锁(一个 NSLock)。请注意,我并不是说它必须在所有线程之间全局共享:只有其中的线程才能访问您的对象。您所说的连续两次锁定是正确的:除非互斥锁是递归的,否则会出现问题。要使用递归互斥锁,您必须使用 NSRecursiveLock 对象。请参阅“线程编程指南”文档,尤其是“同步”部分。【参考方案2】:
您不应该在 Core Data 中使用锁。该文档可能已过时。理想情况下,每个线程应该有一个上下文,并让上下文处理其底层 NSPersistentStoreCoordinator 的锁定。这被认为是目前在多线程应用程序中使用 Core Data 的唯一安全方式。
【讨论】:
以上是关于NSLock 实例应该是“全局的”吗?的主要内容,如果未能解决你的问题,请参考以下文章
我应该为 Vertx 应用程序中的对象创建静态 Vertx 实例吗?
在 .NET 中,使用“foreach”迭代 IEnumerable<ValueType> 的实例会创建一个副本吗?那么我应该更喜欢使用“for”而不是“foreach”吗?