![]() |
1
3
你说得对,这是个问题。定稿器是无用的,它将运行得太晚,无法使用。无论如何,在这之前,代码应该已经严重死锁了。不幸的是,您无法区分a foreach调用movenext/current成员或显式使用它们的客户机代码之间的区别。 不解决,不要这样做。微软也没有这样做,他们有足够的理由回到.NET 1.x中。唯一真正的线程安全迭代器是在getEnumerator()方法中创建集合对象的副本。不过,与集合不同步的迭代器也不是什么乐趣。 |
![]() |
2
2
这似乎太容易出错了。它鼓励以一种对代码的读者不清楚的方式隐式/无声地取出锁的情况,并使关于接口的关键事实可能被误解。
通常,复制常见模式是一个好主意-用
我建议最好的方法是根本不提供线程之间共享的集合的枚举。试着设计整个系统,这样就不需要了。显然,这有时会是一个疯狂的白日梦。
所以接下来最好是定义一个上下文,在这个上下文中
也就是说,当此集合的用户想要枚举它时,他们会这样做:
这使得锁的生存期由一个作用域(由lambda主体表示,工作方式与
实施
注意如何
这意味着即使有人试图滥用接口:
本遗嘱 总是 抛掷,而不是根据时间而神秘地失败。
使用接受这样的委托的方法是管理Lisp和其他动态语言中常用的资源生命周期的一种通用技术,尽管它不如实现
更新
从您的评论中,我看到您需要能够将对集合的引用传递给现有的UI框架,从而期望能够使用集合的常规接口,即直接获取
您唯一实际的选择是在请求枚举器时复制集合。这样,只有在复制时才需要保持锁定。一旦准备好,锁就被释放了。如果集合通常很小,这可能更有效,因此由于锁更短,复制的开销小于性能节省。 建议您使用一个简单的规则是很有吸引力的(大约一纳秒):如果集合小于某个阈值,则进行复制,否则以原始方式执行;动态选择实现。这样您就获得了最佳的性能—通过实验设置阈值,这样拷贝就比持有锁便宜。然而,对于线程代码中的这种“聪明”的想法,我总是会三思而后行(或十亿次),因为如果在某个地方存在对枚举器的滥用呢?如果你忘了处理它,就不会有问题了 除非它是一个大收藏 …隐藏虫子的配方。不要去那儿! “公开一份副本”方法的另一个潜在缺点是,客户无疑会陷入这样的假设:如果某个项目在集合中,它将暴露于世界,但一旦从集合中删除,它将被安全地隐藏。现在就错了!UI线程将获得一个枚举器,然后我的后台线程将从中删除最后一个项,然后开始对其进行变异,错误地认为,因为它被删除了,所以没有其他人能够看到它。 因此,复制方法要求集合中的每个项都有效地拥有自己的同步,在这里,大多数编码人员将假定他们可以通过使用集合的同步来实现这一点。 |
![]() |
3
1
我最近不得不这么做。我这样做的方法是抽象它,这样就有一个内部对象(引用)包含
二者都
实际列表/数组
和
计数(和A
这个
当然,我的方案很简单,我的清单
|
![]() |
4
1
在必须使用的
因为您永远不知道用户何时使用枚举器,所以除了记录用户必须处理对象之外,您没有其他选项。您可能希望建议用户使用
|