如何通过调度并发队列(GCD)实现可重入锁定机制?

时间:2013-11-25 19:02:26

标签: objective-c grand-central-dispatch

我刚读过this post,其解决方案似乎令人信服:

  • 串行队列用于同步访问
  • dispatch_get_specific / dispatch_set_specific用于提供重入功能。

我感兴趣的是,是否有可能推进此方案以实现并发调度队列的重入锁定机制(每次读取都是使用dispatch_sync完成的,写入是使用dispatch_barrier_async完成的,如描述的那样here, see "One Resource, Multiple Readers, and a Single Writer")。

P.S。我想我已经设法使用[NSThread currentThread].threadDictionary here来实现这一点,但我不喜欢处理[NSThread currentThread]因为我依赖GCD。是否可以使用某些棘手的[NSThread currentThread].threadDictionary代码替换dispatch_set_specific/dispatch_get_specific的使用情况?

1 个答案:

答案 0 :(得分:9)

如果我对这个问题发表评论,你在评论链接帖子时问过我。对不起,我花了很长时间,但我记得第一次看到它时,我觉得我没有任何富有成效的说法。但是今天我被提醒了这个话题并回过头来看这个问题,并且想到我会拍摄一下:

总的来说,我建议不要走这条路。正如我在the linked-to/from answer中所解释的那样,使用dispatch_get/set_specific实现递归“锁定”是从不防弹,超越简单的串行案例到单作者/多读者dispatch_barrier_[a]sync的语义不会消除这些问题,并可能引入更多问题。

顺便说一句,如果您只是寻找替代[NSThread threadDictionary]的线程本地存储,可能是非Objective-C API的形式,那么您应该使用pthread_setspecificpthread_getspecific。这些是较低级别的POSIX调用[NSThread threadDictionary](几乎可以肯定)构建的。

退一步:在经验丰富的系统程序员中,有一种非常强烈的感情,即递归锁是一种反复模式,应该避免使用。这是一个interesting treatise on the subject。 (如果你对为什么在POSIX中存在递归互斥体的伪造故事不感兴趣,只需搜索“客观事实”跳转到与这个问题相关的部分。)那篇文章是用更原始的“锁定”来编写的。尽管在一些常见情况下队列可以(有时非常有用)适应模拟锁,但是(由互斥和条件组成)与队列根本不同。然而,即使它们不同,如​​果你考虑到Butenhof对递归原始锁的批评,很快就会发现,在许多递归锁是“坏”的方式中,使用队列来模拟锁是更糟< / em>的。例如,在最基本的级别,你可以解锁锁定模拟队列的唯一方法是返回;有别的方式来释放基于队列的锁。调用其他可能需要递归重新输入该锁的代码,而调用者继续持有该代码,是“锁定”持有时间的潜在无限扩展。

对我有用的一般建议是,“使用最高级别的抽象来完成工作。”在这个问题的上下文中,这将转化为(暂时搁置上述对递归锁定的批评):如果你在Objective-C中工作,并且无论出于何种原因,你想要递归锁定,只需使用{{1 }}。当性能分析告诉您使用@synchronized实际上导致问题时,然后会寻找更好的解决方案(有先见之明,知道“更好的解决方案”可能需要离开所有的递归锁定。)

总而言之,尝试调整GCD的并发队列屏障行为来模拟递归读取器/写入器锁定感觉就像一个失败的命题。充其量,它总是受限于我为串行案例解释over here的限制。在最坏的情况下,你会发布一种最终会降低并发性的模式。