C# 中的有序锁定模式和 ReaderWriterLock

发布于 2024-10-13 15:16:32 字数 318 浏览 3 评论 0原文

与 ReaderWriterLock(或 ReaderWriterLockSlim)一起使用时,有序锁定模式是否可以防止死锁?

显然,该模式可以通过互斥体防止死锁。如果我使用 ((带有读锁的 N 个资源) 和 (带有写锁的 1 或 2 个资源)) 锁定多个资源,它是否仍然可以防止死锁。

例如:(粗体数字代表有写锁的资源)

1 2 3 4 5

2 3 4

1 4 5

Does the ordered locking pattern prevent deadlocks when used with a ReaderWriterLock (or ReaderWriterLockSlim)?

Clearly the pattern prevents deadlocks with a mutex. Does it still prevent deadlocks if I am locking several resources with ((N resources with read locks) and (1 or 2 resources with write locks)).

For example: (Bold numbers represent resources with write locks)

1 2 3 4 5

2 3 4

1 4 5

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遗失的美好 2024-10-20 15:16:32

tl;dr 资源排序也可以防止读写锁出现死锁。

长答案:

画一个这样的等待图:

首先为图中从左到右的所有资源画一个顶点
规定的顺序。

然后,对于每个进程,等待资源,绘制一个顶点,
紧邻等待资源的顶点之前。
如果进程没有等待任何资源,则绘制一个顶点
在最右边,在所有资源顶点之后。

然后从每个进程到其上的资源绘制一条边
进程正在等待并从每个资源向
当前持有该资源的进程。

考虑图上的每条边。有两种情况:

  • 边是Pi -> Ri,即从进程到资源。由于每个
    进程只等待一种资源,我们绘制了
    进程的顶点紧邻其所在资源的左侧
    等待,那么边缘是从左到右。

  • 边缘是Ri -> Pj,即从资源到进程。如果Pj
    不等待任何资源,则其顶点在
    所有资源,因此边缘是从左到右。如果Pj
    正在等待Rk,然后i k,因为进程获取资源
    命令。如果i < k,那么RiRk的左边,Pj
    紧邻 Rk 的左侧(因为我们已经用这种方式绘制了图表),
    因此 Ri 位于 Pj 的左侧,因此边缘再次留给
    右。

由于以这种方式绘制的图形的所有边都是从左到右
对了,那么我们就构建了图的拓扑排序,
因此该图没有循环,因此不会发生死锁。

请注意,重要的是进程等待的事实,而不是原因
等待。因此,无论是否等待互斥锁,
读写锁、信号量或其他任何东西——这种死锁策略
预防对所有人都有效。

tl;dr Resource ordering prevents deadlock for reader-writer locks too.

Long answer:

Draw a wait-for graph like this:

First draw a vertex for all the resources from left to right in the
prescribed order.

Then, for each process, waiting for a resource, draw a vertex,
immediately preceding the vertex of the waited for resource.
If a process is not waiting on any resources, draw a vertex
on the far right, after all the resource vertices.

Then draw an edge from each process to the resource on which that
process is waiting and draw an edge from each resource to the
process, which is currently holding that resource.

Consider each edge on the graph. There are two cases:

  • the edge is Pi -> Ri, i.e. from a process to a resource. Since each
    process is waiting on only one resource and we have drawn the
    process' vertex immediately to the left of the resource it is
    waiting for, then the edge is from left to right.

  • the edge is Ri -> Pj, i.e. from a resource to a process. If Pj is
    not waiting to any resource, then its vertex is on the right of
    all the resources, therefore the edge is from left to right. If Pj
    is waiting to Rk, then i < k, because processes acquire resources in
    order. If i < k, then Ri is on the left of Rk, and Pj is
    immediately on the left of Rk (since we have drawn the grapgh that way),
    hence Ri is on the left of Pj, therefore the edge is again left to
    right.

Since all the edges of the graph drawn this way are from left to
right, then we have constructed a topological sorting of the graph,
hence the graph has no cycles, hence a deadlock cannot occur.

Note that what matters is the fact that a process waits, not why it
waits. Thus, it does no matter whether it waits for a mutex,
read-write lock, semaphore or whatever - this strategy for deadlock
prevention works for all.

爱的那么颓废 2024-10-20 15:16:32

我认为您执行的有序锁定模式是错误的,您必须按顺序获取所有锁。要抢到“4”的写锁,需要先抢到“3”的写锁。对于“5”,您需要获取“3”“4”“5”的写锁。

对于普通锁,有序锁定模式的成本很高,但对于 SRW 锁,它们的成本超级,因为您必须首先扔掉所有读取器。请记住,只有当至少 80% 以上的访问不需要写锁时,SRW 锁才有优势 - 否则它的成本非常,并且使用简单的锁可以做得更好。

更好的是,尝试解耦您的代码,以便您不需要有序锁定(即,我不需要同时访问“3”和“4”中的数据)。这并不总是可行,但您做得越多,您的代码就会越简单。

I think you're doing the Ordered locking pattern wrong, you have to grab all the locks in order. To grab the write lock for "4", you need to first grab the write lock for "3". For "5", you need to grab the write locks for "3" and "4" and "5".

With normal locks, the ordered locking pattern is expensive, but with SRW locks they're super expensive since you have to throw out all the readers first. Remember that SRW locks only are an advantage if at least 80%+ of your accesses don't need the Write lock - it's very expensive otherwise, and you can do far better with a simple lock.

Even better though, is to try to decouple your code so that you don't need the ordered locking (i.e. so I don't need access to the data from '3' and '4' at the same time). This isn't always possible, but your code will be simpler the more you can do this.

清旖 2024-10-20 15:16:32

我尝试在 C# 中实现有序锁,检查是否已按固定顺序获取锁。请参阅http://www.codeproject.com/Tips/563154/OrderedLock-in- Csharp

I attempted an implementation of ordered lock in C# that checks if locks have been acquired in a fixed order. See http://www.codeproject.com/Tips/563154/OrderedLock-in-Csharp

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文