c# – ReaderWriterLockSlim.EnterUpgradeableReadLock()始终是死锁?

c# – ReaderWriterLockSlim.EnterUpgradeableReadLock()始终是死锁?,第1张

概述我对ReaderWriterLockSlim非常熟悉,但我最近尝试在类中实现了EnterUpgradeableReadLock()……很快我意识到当2个或更多线程运行代码时,这几乎肯定是一个保证死锁: Thread A --> enter upgradeable read lockThread B --> enter upgradeable read lockThread A --> trie 我对readerwriterlockslim非常熟悉,但我最近尝试在类中实现了EnterUpgradeableReadLock()……很快我意识到当2个或更多线程运行代码时,这几乎肯定是一个保证死锁:
Thread A --> enter upgradeable read lockThread B --> enter upgradeable read lockThread A --> trIEs to enter write lock,blocks for B to leave readThread B --> trIEs to enter write lock,blocks for A to leave readThread A --> waiting for B to exit read lockThread B --> waiting for A to exit read lock

我在这里错过了什么?

编辑

添加了我的场景的代码示例. Run()方法将由两个或多个线程同时调用.

public class Deadlocker{    private Readonly readerwriterlockslim _lock = new readerwriterlockslim(LockRecursionPolicy.SupportsRecursion);    public voID Run()    {        _lock.EnterUpgradeableReadLock();        try        {            _lock.EnterWriteLock();            try            {                // Do something            }            finally            {                _lock.ExitWriteLock();            }        }        finally        {            _lock.ExitUpgradeableReadLock();        }    }}
解决方法 OP之后很长一段时间,但我不同意目前接受的答案.

声明线程B – >输入可升级的读锁定不正确.从the docs起

Only one thread can be in upgradeable mode at any time

并回应您的意见:它旨在用于读写模式的非常不同的用法.

TL; DR.可升级模式很有用:

>如果作者必须在写入之前检查共享资源,并且(可选)需要避免与其他作者的竞争条件;
>它应该不会阻止读者,直到它100%确定它必须写入共享资源;
>并且很可能一个编写者决定在执行检查后不应该写入共享资源.

或者,在伪代码中,这里:

// no other writers or upgradeables allowed in here => no race conditionsEnterUpgradeableLock(); if (isWriterequired()) { EnterWriteLock(); DoWrite(); ExitWriteLock(); } ExitUpgradeableLock();

给予“更好的表现”÷比这:

EnterWriteLock(); if (isWriterequired()) { DoWrite(); } ExitWriteLock();

如果独占锁定部分由于使用SpinLock而需要很长时间,则应小心使用.

类似的锁构造

可升级锁与sql服务器SIX lock(与Intent共享以获得eXclusive)惊人相似†.

>要在这些术语中重写上述语句,可升级锁定说“作者打算写入资源,但希望与其他读者共享,同时[双]检查条件,看它是否应该独立锁定并执行写“‡.

如果没有Intent锁,您必须在eXclusive锁中执行“我应该进行此更改”检查,这会损害并发性.

为什么你不能共享可升级?

如果可升级锁可与其他可升级锁共享,则可能与其他可升级锁所有者具有竞争条件.因此,您需要在写锁定内部进行一次检查,从而消除了检查的好处,而不会阻止其他读取 *** 作.

如果我们将所有锁定等待/进入/退出事件视为顺序,并且锁定内部的工作是并行的,那么我们可以用“大理石”形式编写一个场景(e enter; w wait; x exit; cr check resource; mr mutate资源; R共享/读取; U意图/可升级; W eXclusive / Write):

1--eU--cr--wW----eW--mr--xWxU--------------2------eR----xR----------------eR--xR------3--------eR----xR--------------------------4----wU----------------------eU--cr--xU----

用语言:T1进入Upgradeable / Intent锁. T4等待Upgradeable / Intent锁定. T2和T3输入读锁. T1同时检查资源,赢得比赛并等待eXclusive / Write锁定. T2& T3退出锁. T1进入eXclusive / Write锁定并进行更改. T4进入可升级/意图锁定,不需要进行更改并退出,而不阻止T2,同时执行另一次读取.

在8个要点……

可升级锁是:

>任何作家使用;
>谁可能先检查,然后决定不以任何理由执行写入(丢失竞争条件,或以Getsert模式);
>谁不应该阻止读者,直到它知道它必须执行写;
>因此它将取出一个独占锁并这样做.

如果下列之一适用(包括但不限于),则不需要升级:

> writelock-check-Nowrite-exit的读者和作者之间的争用率大约为零(写入条件检查超快) – 即可升级的构造对读者吞吐量没有帮助;
>在Write锁中写入一次的写入器的概率是〜1,因为:

> ReadLock-Check-WriteLock-DoubleCheck是如此之快,它只会导致每万亿次写入失败者;
>所有变化都是独一无二的(所有变化都必须发生,种族不可能存在);要么
>“最后的变化获胜”(所有变化仍然必须发生,即使它们不是唯一的)

如果锁(…){…}更合适,也不是必需的,即:

>重叠读取和/或写入窗口的概率很低(锁定可以同样防止非常罕见的事件,因为保护极有可能的事件,更不用说简单的内存屏障要求)
>你所有的锁定都是可升级或写入,永远不会读取(‘duh’)

÷“性能”由您来定义

†如果您将锁定对象视为表,并将受保护资源视为层次结构中较低的资源,则此类比近似成立

‡读取锁定中的初始检查是可选的,可升级锁定内的检查是强制性的,因此可以单个或双重检查模式使用.

总结

以上是内存溢出为你收集整理的c# – ReaderWriterLockSlim.EnterUpgradeableReadLock()始终是死锁?全部内容,希望文章能够帮你解决c# – ReaderWriterLockSlim.EnterUpgradeableReadLock()始终是死锁?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1242380.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存