【发布时间】:2013-12-16 19:21:06
【问题描述】:
锁定不同(动态)数量的对象/键的最佳策略是什么?
考虑这样的场景,当在多个对象上获得锁时(对象数组是动态的,无法预测),线程只能继续执行任务(事务)。在这个例子中,一个 ID 可以代表一个 Object,它需要作为“事务”的一部分进行修改。
示例:
线程:要锁定的对象(作为事务的一部分)
T1: A B C D
T2: B D
T3: A D
编辑:改进示例
显然,进行顺序动态锁定会导致所有线程死锁,因为T1 可以获得A 的锁定,而T2 获得B 上的锁定,而T3 获得@987654327 上的锁定@。 T1 等待T2 释放B,T2 等待T3 释放D,T3 等待T1 释放A。
实现这种多对象锁定有哪些可能的选择?
这个问题部分是理论上的,部分是实际的,因为它必须在 C# / .NET 中解决
可能的解决方案:
为了既保持并行性又保持正确的锁定,我想到了以下方案:
两个队列:
- 顺序队列(仅由 1 个线程提供服务,因此是顺序的)
- 并行队列(由线程池提供服务)
当对 N 个对象的请求到达时,检查每个对象 ID 以及是否为每个 ID 增加锁计数(这可以是 Dictionary<int, int> - <Id, Lock Count>)。
如果所有 ID 都被“锁定”(注意实际上没有发生锁定),即第一次请求,则将请求放入并行队列 ELSE 将请求放入顺序队列中
这种混合方法允许按顺序处理“竞争”请求,并允许并行处理非竞争请求。
【问题讨论】:
-
为什么 T2 等待 T1 释放 A? T2 没有锁定 A
-
@dcastro 因为 T1 抢了 A 然后 B,同时 T2 想要 B,所以它会等待 T1 完成 C 和 D 才释放 B。
-
是的,同意这个例子可以改进——关键是有问题的场景涉及两个线程持有一些键,另一个线程也想要这些。
-
考虑 T1:A B -- T2:B A,其中每个人都抓住了他们的第一把锁,而不是他们的第二把。这将陷入僵局。您需要确保您的代码不会发生这种情况,这并不总是那么容易。
-
@DavidHaney 您的序列是有效的,但在给出的示例中,B 被 T2 抓取。
标签: c# .net multithreading