可重入读写锁实现?

17
我是一名有经验的.NET程序员,正在尝试iOS开发。在.NET中,我最喜欢的多线程构造之一是ReaderWriterLock。它允许多个读取器或一个写入器。我现在在iOS中真正缺失的一个特性是锁的可重入性。也就是说,只要读取线程释放相同数量的锁定,它们就可以多次获取读取锁定。同样地,单个写入线程可以多次获取锁定,只要它通过等效数量释放锁定即可。
我已经研究了iOS框架,但没有任何构造物似乎提供相同的支持,包括可重入性。我还研究了pthread库。我找到了rwlock,但它不允许可重入性。
是否有任何在iOS上允许可重入读写锁的方法?
2个回答

19

是的,@synchronized指令是可重入的。请参阅多线程编程指南中的Using the @synchronized Directive以及ObjC编程语言中的Threading

尽管如此,在iOS中你几乎永远不应该使用这个。在大多数情况下,你可以避免所有类型的锁,更别说非常耗费时间的(慢速)可重入锁了。请查看并阅读《并发编程指南》及特别是其中的Migrating Away from Threads一节,详细了解基于队列的方法,这些方法比手动线程管理和锁更适合iOS。

例如,使用Grand Central Dispatch,读者/作者锁的工作方式如下:

- (id)init {
   ...
   _someObjectQueue = dispatch_queue_create("com.myapp.someObject", 
                                            DISPATCH_QUEUE_CONCURRENT);
 }

// In iOS 5 you need to release disptach_release(_someObjectQueue) in dealloc,
// but not in iOS 6.

- (id)someObject {
  __block id result;
  dispatch_sync(self.someObjectQueue, ^{
    result = _someObject;
  });
  return result;
}

- (void)setSomeObject:(id)newValue {
  dispatch_barrier_async(self.queue, ^{
    _someObject = newValue;
});

该方法允许无限制的并行读操作,独占式写操作,并确保写操作不会饿死且读写操作串行化,同时避免除非实际有争用否则不进行任何内核调用。也就是说它非常快速和简单。

当读取操作发生时,您将请求加入队列并等待其处理。当写操作发生时,它会将一个屏障请求加入队列以更新值,这需要该队列中当前没有运行其他请求。使用此构造方式,开发人员无需管理任何锁,只需按照希望它们运行的顺序将事物放入队列即可。


1
@synchronized是可重入的,但不支持多个读取器。使用GCD需要对我现有的代码进行一些重大的重构。 - Askable
你说得对,@synchronized不支持多个读者。这种方法在Cocoa中很少见,我也不熟悉除了pthread_rwlock_init之外的更好的解决方案。正如我所说,这种锁定非常低效,在iOS和现代Mac中有更快、更安全、更简单的机制,如GCD和NSOperationQueue。在旧版的Mac中,协作式(runloop)多任务处理是首选。.NET从Java继承了它对线程和锁的喜爱。ObjC不鼓励显式线程处理。Cocoa与.NET不同,值得学习iOS中的Cocoa方法。 - Rob Napier
(是的,我知道这并没有真正回答你的问题。对此我感到抱歉。) - Rob Napier

3

来自iOS 线程编程指南

系统仅支持使用POSIX线程的读写锁。有关如何使用这些锁的更多信息,请参见pthread手册页。

所以我猜如果pthread不支持可重入性,答案就是否定的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接