iOS - NSCache如何确保线程安全

时间:2015-09-07 14:35:46

标签: ios multithreading thread-safety nscache

我想实现一个线程安全的MutableDataContainer。当然,我可以简单地为写入和读取操作添加一个锁,但在我的项目中,我需要经常读取数据,所以我不想使用这种方法。

有谁知道NSCache是如何实施的?

1 个答案:

答案 0 :(得分:0)

我不确定NSCache具体使用哪种锁定机制,但是我建议使用5种解决方案中的一种,尤其是在针对Apple平台的现代开发中,这可能是实现NSCache的方法之一。可能有5种以上,此列表并不详尽。我只是不包括更多内容,因为我认为Apple不会使用此处未包含的方法。

以下所有方法都行得通,但是我将尽一切努力使自己听起来似乎对哪种方法更好(我们将看看效果如何)有看法,因为这并不是您真正要问的问题。另外,在这个问题上有很多意见,我不想为此大火。我将基于这些方法和我对Apple的看法,就如何实现NSCache提出自己的看法。

  1. pthread库的pthread RW锁。这是专门为同步而设计的,并且具有锁所能提供的性能,而这与简单的互斥锁(RW锁实际上在使用)无关。对于读取,您可以使用pthread_rwlock_rdlock获得一个锁,对于写入,您可以使用pthread_rwlock_wrlock获得一个锁。在下面,这本质上是一个递归锁,并且除非有写操作,否则实际上不应该阻止读取。这优化了更常见的读取路径,并安全地说明了较不常见的写入路径。对于更不常见的读/写操作,必须从根本上将其升级为写操作。使用pthread锁(或互斥锁)时,您可以根据自己的代码逻辑和内部定义良好的条件来优化锁,尽管我在这里不做介绍。

  2. GCD库的串行队列-使用串行队列时,使用disaptch_sync进行读取,使用dispatch_async进行写入。这与pthread RW锁在优化公用路径方面有所不同,因为读取和写入都是串行的。尽管它确实依赖GCD通过其底层队列优化来优化读取(例如,GCD确定何时为dispatch_sync调用适当地阻塞)。对于更不常见的读/写操作,您只需将其视为读并使用dispatch_sync。再说一次,因为这种方法与以前的方法有一个重要的不同之处,尽管读取应该通过GCD进行快速和优化,但它们仍然是串行的,从技术上讲仍然是相互阻塞的。

  3. GCD库的并发队列-使用并发队列时,将dispatch_sync用于读取,将dispatch_barrier_async用于写入。对于特殊的读/写情况,专门为此目的制作了dispatch_barrier_sync。在这个世界上,读取之间不会相互阻塞,也不会阻塞,直到遇到障碍为止,该障碍是为写入和读/写保留的。这种方法还依赖于GCD来优化读取,但是通过使用并发队列,您选择不进行串行读取。因此,基本上由您来控制必须是串行的事物,并在这些操作需要它时使用屏障。

  4. 基金会框架的NSLock-这是基金会框架的经典构造。尽管它的原始实现可能有所不同,但是最近我研究了它的内部构造,并且在我测试过的所有情况下,它本质上都是一个对应于pthread实现的Objective-C包装。

  5. Objective-C的@synchronized()-这是内置的Objective-C函数/关键字,提供锁定和异常处理。实际上,它的下面是一个带有异常处理程序的NSLock。使用它时,它既适用于读取,也适用于写入。在内部,它们被相同地对待,因此没有一个相对于另一个进行优化。您的锁与您传递给@synchronized(obj)函数的对象相关联。因此从本质上讲,无论在相应的``@synchronized(){}`块中如何使用或更改对象,您都将锁定对该对象的访问。

每种方法都有更多的细节和警告,尽管如果我是一个博彩人(但我不是),并且基于此之后我会涉及的几件事,我会说苹果正在使用方法# 3用于NSCache。

原因1:Apple关注性能,尤其是Foundation。自GCD成立以来,他们已经在GCD上投入了大量资金,并将继续对其进行投资。创建GCD的大多数原因是基于在不牺牲性能的情况下尽可能多地删除样板。我想说的是,Apple可能会在Foundation内部的一些地方对他们的建议dog之以鼻,而NSCache可能就是其中之一。

原因2:有点“原因1继续”,最近有证据表明苹果公司对GCD的投资以及对@synchonized()的投资不足,这在Swift中可以看到。 GCD是Swift中首选的同步方法。