简单聊聊C#中lock关键字

为了避免多个线程同时操作同一资源,引起数据错误,通常我们会将这个资源加上锁,这样在同一时间只能有一个线程操作资源。在C#中我们使用lock关键字来锁定资源,那lock关键字是如何实现锁定的呢?

我们先看一段代码,非常简单的单例,相信你闭着眼睛也能写出来。代码如下:

上面的代码我就懒得解释了。我们重点关注lock(locker)这行,就是这行限制了多个线程对大括号内代码的同时访问。下面我们就来讲一个原理。不过讲原理之前,还得和大家确认一个知识点,其实lock只是语法糖,其实现其实是Monitor类,所以上面的代码和下面的代码是相等。代码如下:

没有异议的话,我们接着讲。我们还是看lock(locker)这一行,简单地想一想,lock关键字把locker对象锁住了,别的线程就进不来了,那它是怎么锁的呢?是在对象上打了什么标记吗?是把线程ID打到标记吗?我们先看一下堆中locker的对象结构。如下图:

对象在堆中除了数据区以外,还有两片区域:MethodTableRef、SyncBlockValue。其中MethodTableRef是指向MethodTable中这个类型(Type)定义,简单说就是这个对象是什么class定义的,这个不是我们今天讨论的重点,就过了。

我们重点看一下SyncBlockValue,这个值为DWORD类型,占用4个字节,也就是32位。这个值主要用来表示对象的不同功能,具体什么功能,要看这个32位如何赋值。一般将32位分为两段,前6位用以表示不同的功能,后26位用以表示对象的hash值、或者是SyncBlock的索引值。如下图:

回到lock(locker)这个主题上。其实你也应该猜到,如果想实现lock(locker),只要在locker的前六位功能位上设置一个标识位,标识这个对象已经被锁住就行。但具体被哪个线程锁住要记在哪边呢?这时就要用到后面26位了。这时后26位会指向g_pSyncTable的某一项。g_pSyncTable是CLR维护的一个包SyncBlock项的全局数组。这时的结构如下图:

我们结合上图再来回顾一下整个流程:比如有两个线程:线程A、线程B。线程A执行到lock(locker)这一行时,会先检查locker的6个功能位中有没有没锁住标识位(假如第五位表示锁),如果没有锁,则将第五位标为1(不一定是1,这里只是举例),然后到g_pSyncTable数组中申请一个SyncBlock,将当前线程ID等信息记录在里面,然后将这个SyncBlock的地址赋予locker对象的后26位值,这样资源就被线程A锁住了。这时线程B也执行到lock(locker)这一行,它检查前第五位,发现被锁住了,就会到SyncBlock检查锁住的线程ID是否和自己一致,不一致的话,它就会一直等待,直到线程A释放锁。

以上只是粗略地讲述一下锁的底层原理,可能有很多描述不准确的地方,比如哪个功能位表示锁,其实我也不太清楚,但大概原理应该没错。

最后留个问题:如果锁住的对象同时又想获取HashCode,该如何存储并得到呢?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea如何导入java工程_Eclipse java web项目 ,导入IntelliJ IDEA 完整操作!

或许你用惯了Eclipse,有点排斥其他工具了,你写框架的时候,编译速度是不是特别慢啊?有时候还超过45秒,自动取消运行!有时候代码是正常的,却无端端报错?下午吃个饭回来又好了&#xff…

行业思考 | 互联网对传统行业的降维打击

【行业思考】| 作者 / Edison Zhou这是EdisonTalk的第301篇原创内容在周一发布的推文《我在传统行业做数字化转型之预告篇》中,我提到互联网的发展和和竞争对传统行业起到了降维打击的作用,于是就有童鞋私下问我,为何这么说。今天就跟你聊聊这…

BCVP开发者说第一期:Destiny.Core.Flow

沉静岁月,淡忘流年1项目简介Destiny.Core.FlowDestiny.Core.Flow是基于.NetCore平台,轻量级的模块化开发框架,Admin管理应用框架,旨在提升团队的快速开发输出能力,由常用公共操作类(工具类、帮助类&#xf…

.NET Core 取消令牌:CancellationToken

在 .NET 开发中,CancellationToken(取消令牌)是一项比较重要的功能,掌握并合理的使用 CancellationToken 可以提升服务的性能。特别在异步编程中,我常常会以创建 Task 的方式利用多线程执行一些耗时或非核心业务逻辑&a…

java char short区别_java 彻底理解 byte char short int float long double

遇到过很多关于 数值类型范围的问题了,在这做一个总结,我们可以从多方面理解不同数值类型的所能表示的数值范围在这里我们只谈论 java中的数值类型首先说byte:这段是摘自jdk中 Byte.java中的源代码从这里可以看出 byte的取值范围:…

程序员过关斩将--从未停止过的系统架构设计步伐

“首先,这篇文章肯定会得罪一些人“其次,此文只代表我个人的意见,仅供参考从分层说起谈到系统架构的分层和系统领域边界的划分,每个架构师,每个技术经理,甚至每个程序员都有自己的一套想法。无论是怎么样的…

BCVP第2期:项目已完成升级.NET5.0

(是时候拿出来这种图了)1开心的锣鼓想必这两天最热闹的几个词语,就是c#9.0、.net5.0还有conf大会了吧,当然还有大一统。其实,早在2019年年中,就已经引入了.NET5.0了,然后从2020-03-16开始,就一直在说.NET5.…

如何在ASP.NetCore增加文件上传大小

关注架构师高级俱乐部开启架构之路不定期福利发放哦~架构师高级俱乐部读完需要7分钟速读仅需 3 分钟/ 如何在核心中增加文件 ASP.NET 大小 /从ASP.NET 2.0开始最大请求正文大小限制为30MB (28.6 MiB)。在正常情况下,无需增加 HTTP 请求 body …

java完全二叉树最小堆_Java实现最小堆一

Java实现最小堆一堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值。最大堆和最小堆是二叉堆的两种形式。最大堆:根结点的键值是所有堆结点键值中最大者。最小堆:根结点的键值是所有堆结…

一个 Task 不够,又来一个 ValueTask ,真的学懵了!

一:背景 1. 讲故事前几天在项目中用 MemoryStream 的时候意外发现 ReadAsync 方法多了一个返回 ValueTask 的重载,真是日了狗了,一个 Task 已经够学了,又来一个 ValueTask,晕,方法签名如下:publ…

Magicodes.IE 3.0重磅设计畅谈

Magicodes.IE 3.0重磅设计畅谈总体设计图Magicodes.IE导入导出通用库,支持Dto导入导出、模板导出、花式导出以及动态导出,支持Excel、Csv、Word、Pdf和Html。IE在去年年底重构一次之后,经过这么长时间的迭代,又迎来了瓶颈。根据本…

php引用类,thinkphp引用类的使用

比如发送邮件类phpmailer1.将核心文件放入ORG目录下2.在使用的地方,引入这个类文件如何引入呢?import(.ORG.phpmailer);这个表示引入当前项目中的ORG中的phpmailer.class.php文件3.引入之后就可以使用文件中的类了public function sendEmail() {import(.…

Net5 已经来临,让我来送你一个成功

没错,那就是“下载成功”。现在,已经可以急速下载.Net5 docker 镜像 .Net 5 进行今天已经正式发布,想必各位已经通过各种渠道了解到了此次发布的所有内容。并且也都体会到了这次凑成三连的金 scott 是什么效果(啊哈,三…

推荐几款强大流行的BI系统

高级架构师俱乐部 读完需要2分钟速读仅需 1 分钟企业在日常运营过程中,需要根据公司实时经营数据来做未来决测或者发现经营中的问题,在此过程中离不开对数据的分析,而平常利用 excel 等方式极大的提高了领导层快速做出决测的成本&#xff0c…

php 4位数字不足补零,php实现数字不足补0的方法

php实现数字不足补0的方法发布时间:2020-08-28 09:51:06来源:亿速云阅读:100作者:小新这篇文章将为大家详细讲解有关php实现数字不足补0的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大…

起点低,怎么破?

职场&认知洞察 丨 作者 / findyi这是findyi公众号分享的第91篇原创文章洋友问:“洋哥,我北漂多年,专科毕业从农村出来,感觉做什么都不顺,我该怎么办”。和他聊了聊,他毕业后就来北京打工,尝…

C# Span 源码解读和应用实践

一:背景 1. 讲故事这两天工作上太忙没有及时持续的文章产出,和大家说声抱歉,前几天群里一个朋友在问什么时候可以产出 Span 的下一篇,哈哈,这就来啦!读过上一篇的朋友应该都知道 Span 统一了 .NET 程序 栈 …

[C#.NET 拾遗补漏]12:死锁和活锁的发生及避免

多线程编程时,如果涉及同时读写共享数据,就要格外小心。如果共享数据是独占资源,则要对共享数据的读写进行排它访问,最简单的方式就是加锁。锁也不能随便用,否则可能会造成死锁和活锁。本文将通过示例详细讲解死锁和活…

64岁Python之父加入微软 | 谁说大龄程序员无出路

喜欢就关注我们吧!现年 64 岁的 Python 创始人 Guido van Rossum 退休一年后再度复出,今天宣布已加入微软开发者部门 (Developer Division).我觉得退休生活乏味又无趣,因此已加入微软开发者部门。做什么工作?选择太多了&#xff0…

JAVA中的GridView每一个赋值,在ASP.NET 2.0中操作数据之六十二:GridView批量更新数据...

导言:在前面的教程,我们对数据访问层进行扩展以支持数据库事务.数据库事务确保一系列的操作要么都成功,要么都失败。本文我们将注意力转到创建一个批更新数据界面.在本文,我们将创建一个GridView控件,里面的每一行记录…