问题描述
我刚刚阅读了这发布,其解决方案似乎令人信服:
I have just read this post, and its solution seems convincing:
- 串行队列用于同步访问
- dispatch_get_specific/dispatch_set_specific用于提供重入功能.
我感兴趣的是,是否有可能改进此方案以实现并发调度队列的重入锁定机制(每次读取都使用dispatch_sync完成,写入使用dispatch_barrier_async完成,如下所述) 在此处,请参阅一个资源,多个读者和一个作家").
What I am interested at is if it is possible to advance this scheme to implement reentrant locking mechanism for concurrent dispatch queue (each read is done using dispatch_sync, write is done using dispatch_barrier_async, like is described here, see "One Resource, Multiple Readers, and a Single Writer").
P.S.我认为我已经设法使用[NSThread currentThread].threadDictionary
此处,但是我不喜欢与[NSThread currentThread]
打交道,因为我依赖GCD.是否可以用一些棘手的dispatch_set_specific/dispatch_get_specific
代码替换[NSThread currentThread].threadDictionary
的用法?
P.S. I think I've managed to implement this using [NSThread currentThread].threadDictionary
here, but I don't like dealing with [NSThread currentThread]
since I rely on GCD. Is it possible to replace the usage of [NSThread currentThread].threadDictionary
with some tricky dispatch_set_specific/dispatch_get_specific
code?
推荐答案
您在对链接帖子的评论中问我是否要对此问题发表评论.抱歉,我花了很长时间,但是我记得我第一次看它时,我觉得自己没有什么能说的.但是我今天想起了这个话题,然后又回到了这个问题,以为我会出手:
You asked me in a comment on the linked post if I would comment on this question. Sorry I took so long, but I remember the first time I looked at it I didn't feel like I had anything productive say. But I was reminded of this topic today and came back across this question and figured I'd take a shot:
总的来说,我建议不要走这条路.正如我在链接到/来自答案的链接中所述,用dispatch_get/set_specific
实现递归锁"是永远不会防弹,并超越简单的序列化案例到dispatch_barrier_[a]sync
的单写/多读语义,并不能消除这些问题,并且可能会引入更多问题.
In general, I would suggest not going down this road at all. As I explained in the linked-to/from answer, implementing a recursive "lock" with dispatch_get/set_specific
is never bulletproof, and going beyond the simple, serial case to the one-writer/many-readers semantic of dispatch_barrier_[a]sync
isn't going to remove those problems, and would probably introduce even more issues.
顺便说一句,如果您正在寻找[NSThread threadDictionary]
的替代品,用于线程本地存储,也许是以非Objective-C API的形式,那么您应该使用pthread_setspecific
和pthread_getspecific
.这些是较低级别的POSIX调用,(几乎可以肯定)基于[NSThread threadDictionary]
构建.
As an aside, if you're just looking for an alternative to [NSThread threadDictionary]
for thread-local storage, perhaps in the form of a non-Objective-C API, then you should use pthread_setspecific
and pthread_getspecific
. These are the lower level POSIX calls upon which [NSThread threadDictionary]
is (almost certainly) built.
退后一分钟:经验丰富的系统程序员中有一个强烈的想法,即递归锁是一开始的反模式,应避免使用.这是关于该主题的有趣的论文. (如果您对POSIX中为什么存在递归互斥体的伪传说不感兴趣,只需搜索客观事实"即可跳到与该问题相关的部分.)该部分用更原始的锁"编写(由互斥和条件组成),与队列有根本的区别,尽管事实上在某些常见情况下队列可以(有时非常有用)进行模拟锁.但是,即使它们有所不同,但如果考虑到Butenhof对递归原始锁的批评,很快就会发现,在许多方式中递归锁是不良"的,使用队列模拟锁是 worse .例如,在最基本的级别上,解锁队列模拟锁的唯一方法是返回. 没有其他方法来释放基于队列的锁定.调用其他代码,而在调用者继续按住该代码的同时,可能需要递归地重新输入该锁定,这可能是锁定"时间的无限延长.
Stepping back for a minute: There is a pretty strong sentiment among veteran systems programmers that recursive locks are an anti-pattern from the get-go, and are to be avoided. Here is an interesting treatise on the subject. (If you aren't interested in the apocryphal tale of why recursive mutexes exist in POSIX, just search for "the objective facts" to jump to the part that's relevant to this question.) That piece is written in terms of more primitive "locks" (made up of mutexes and conditions), which are fundamentally different from queues, despite the fact that queues can be (sometimes quite usefully) adapted to simulate locks in some common cases. However, even though they're different, if you consider the criticisms Butenhof levies against recursive primitive locks, it quickly becomes evident that in many of the ways that recursive locks are "bad", using queues to simulate locks is worse. For instance, at the most basic level, the only way you can unlock a lock-simulated-by-a-queue is to return; there is no other way to release a queue-based lock. Calling out to other code which may need to recursively re-enter that lock, while the caller continues to hold it, is a potentially unbounded extension of the time the "lock" is held.
一条对我有用的一般建议是:使用最高级别的抽象来完成工作."在此问题的上下文中,这将转换为(暂时忽略对递归锁的上述批评):如果您在Objective-C中工作,并且由于某种原因想要递归锁,则只需使用@synchronized
.当性能分析告诉您使用@synchronized
确实在引起问题时,然后查找更好的解决方案(具有远见之明,即更好的解决方案"可能需要远离递归锁在一起.)
A piece of general advice that has served me well is, "Use the highest level abstraction that gets the job done." In the context of this question, that would translate to (setting aside the aforementioned criticisms of recursive locking for the moment): If you're working in Objective-C and, for whatever reason, you want recursive locks, just use @synchronized
. When performance analysis tells you that your use of @synchronized
is actually causing you a problem, then look into better solutions (with the foresight to know that "better solutions" will probably require moving away from recursive locks all together.)
总而言之,尝试调整GCD的并发队列屏障行为以模拟递归读取器/写入器锁定感觉像是一个失败的提议.充其量,它总是会受到我在串行情况下在此处所解释的限制的约束.最糟糕的是,您正在发布一种最终降低并发性的模式.
In sum, trying to adapt GCD's concurrent queue barrier behavior to simulate a recursive reader/writer lock feels like a losing proposition. At best, it would always be subject to the limitations that I explained over here for the serial case. At worst, you're promulgating a pattern that ultimately reduces concurrency.
这篇关于如何通过调度并发队列(GCD)实现可重入锁定机制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!