首页 新闻 搜索 专区 学院

ReaderWriterLockSlim 官方文档中这样说的

0
悬赏园豆:50 [已解决问题] 解决于 2022-08-08 09:30

ReaderWriterLockSlim 官方文档中这样说的,

中文:

ReaderWriterLockSlim 不是线程中止安全。 不应在访问线程的环境中使用,例如.NET Framework。 如果使用 .NET Core 或 .NET 5+,则应该很好。 Abort .NET Core 不支持,在 .NET 5 及更高版本中 已过时 。

英文:

ReaderWriterLockSlim is not thread-abort safe. You should not use it in an environment where threads accessing it can be aborted, such as .NET Framework. If you're using .NET Core or .NET 5+, it should be fine. Abort is not supported in .NET Core and is obsolete in .NET 5 and later versions.

这我就不理解了,这个在 .NET 6 中到底是所谓的 it should be fine,还是 is obsolete 呢?

我.NET 6 中使用 Singleton 模式注入后,在 _cacheLock.EnterWriteLock(); 之后调用接口使用了 await HttpGet,然后我调试发现,当代码执行了 await 之后 IsWriteLockHeld 被重置成了 false(EnterWriteLock 之后应该是 true),最后在我要 _cacheLock.ExitWriteLock(); 时因为 IsWriteLockHeld = false,导致报错。

下面是代码:

//设置读取锁
        _cacheLock.EnterUpgradeableReadLock();

        try
        {
            if (this.CheckToken()) return this;

            //更新为写入锁
            _cacheLock.EnterWriteLock();

            //获取新的Token
            var url = string.Format(WorkConfig.UrlConfig.GetTokenUrl, this.CorpId, this.CorpSecret);
            var result = await url.SetHttpMethod(HttpMethod.Post).SendAsAsync<AccessTokenResultModel>();
            if (result == null)
                throw new Exception("获取访问 Token 失败!");
            
            result.CheckError();

            
            //填充值
            this.AccessToken = result.AccessToken;
            this.ExpiresIn = result.ExpiresIn;
            this.ExpireDate = DateTime.Now.AddSeconds(this.ExpiresIn);

            _cacheLock.ExitWriteLock();
        }
        finally
        {
            //释放锁
            _cacheLock.ExitUpgradeableReadLock();
        }

于是我修改了代码,尝试用 Wait() 的方式,结果真的就过了,下面是修改后的代码

//设置读取锁
        _cacheLock.EnterUpgradeableReadLock();

        try
        {
            if (this.CheckToken()) return this;

            //更新为写入锁
            _cacheLock.EnterWriteLock();

            //获取新的Token
            var url = string.Format(WorkConfig.UrlConfig.GetTokenUrl, this.CorpId, this.CorpSecret);
            var resultAction = url.SetHttpMethod(HttpMethod.Post).SendAsAsync<AccessTokenResultModel>();
            resultAction.Wait();
            var result = resultAction.Result;
            if (result == null)
                throw new Exception("获取访问 Token 失败!");
            
            result.CheckError();

            
            //填充值
            this.AccessToken = result.AccessToken;
            this.ExpiresIn = result.ExpiresIn;
            this.ExpireDate = DateTime.Now.AddSeconds(this.ExpiresIn);

            _cacheLock.ExitWriteLock();
        }
        finally
        {
            //释放锁
            _cacheLock.ExitUpgradeableReadLock();
        }

于是就有两个疑问了:
第一、ReaderWriterLockSlim 不支持 await,是否有什么可以支持的类可以代替呢
第二、await 和 使用 .Wait() 然后 Result 的方式有什么不同的,什么表现出的现象不一样,我理解的 await 不应该就是 .Wait() 之后取 Result 吗?

求大神帮看看

程序员丁的主页 程序员丁 | 初学一级 | 园豆:119
提问于:2022-08-05 16:41
< >
分享
最佳答案
0

Abort is not supported in .NET Core and is obsolete in .NET 5 and later versions.

它的意思是说 线程终止的方法 在.net 5 之后已经标记为过时的方法了. 不会被使用了. 所以 "it should be fine".

第一、ReaderWriterLockSlim 不支持 await,是否有什么可以支持的类可以代替呢

可以考虑用 SemaphoreSlim 替换, 或者 asyncreaderwriterlock 也可以

第二、await 和 使用 .Wait() 然后 Result 的方式有什么不同的,什么表现出的现象不一样,我理解的 await 不应该就是 .Wait() 之后取 Result 吗?

他们的机制不一样, await 涉及到线程上下文切换, 比如说你await之前当前线程id是1, await之后的线程id就可能变成2.
Wait 是挂起当前的线程, 等任务完成后在唤醒当前线程.

最后补充一下为什么线程切换之后不行:
官方原话, 在await这个场景下 可以翻译成: 调用退出方法的线程必须是调用进入的那个线程.

A thread can exit the modes it has entered in any order, as long as it exits each mode exactly as many times as it entered that mode. If a thread tries to exit a mode too many times, or to exit a mode it has not entered, a SynchronizationLockException is thrown.
收获园豆:50
czd890 | 专家六级 |园豆:12597 | 2022-08-05 23:14
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册