架构师_程序员_码农网

查看: 176|回复: 0

[资料] .NET/C# Lock 锁原理 Monitor 深入讲解

[复制链接]
发表于 2021-4-29 09:54:10 | 显示全部楼层
该lock语句获取给定对象的互斥锁,执行一个语句块,然后释放该锁。持有锁时,持有锁的线程可以再次获取并释放该锁。任何其他线程都被阻止获取该锁,并等待直到释放该锁。

回顾:

.net/c# 用户多线程并发lock(string){...}详解
https://www.itsvse.com/thread-7764-1-1.html

使用 lock 代码

等同于

可以认为 Lock 的底层代码就是 Monitor 实现的。

由于代码使用try ... finally块,因此即使在lock语句主体中引发异常,也会释放该锁。

您不能在语句主体中使用await运算符lock。您不能在语句主体中使用await运算符lock。您不能在语句主体中使用await运算符lock。您不能在语句主体中使用await运算符lock。这句话非常重要!

文档:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

我自己测试代码,使用 Task 获取锁,并使用 await 阻塞,代码如下:

再多次执行如下代码后,执行结果不符合预期。

QQ截图20210429094919.jpg

为什么呢?如果试图在lock块中使用await关键字时使用lock关键字,会得到这个编译错误:cannot await in the body of a lock statement。原因是在await完成之后,该方法可能会在一个不同的线程中运行,而不是await关键字之前的线程(调用线程)。lock关键字需要同一个线程中获取锁和释放锁
修改代码,可以更直观的看到原因:

获取锁的线程Id和释放锁的线程Id,明显不在一个线程上面,所以造成无法成功释放锁,如下图:

QQ截图20210429095916.jpg

尝试修改代码,使用 thread 测试,执行多次,都符合预期,代码如下:

QQ截图20210429095142.jpg

(完)





上一篇:(转).NET/C# 将文件夹打包成 zip 文件
下一篇:Redis 使用 Lua 脚本详解
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:help@itsvse.com

QQ|手机版|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2021-5-17 17:16

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表