利用 Monitor.TryEnter 来规避 .NET 线程死锁的源代码

C# Monitor类 使用详解 阅读详情

在开发多线程的应用程序时,我们会大量用到 lock (...) {} 块。如果 lock 的对象比较多,非常容易发生死锁。死锁的发生很难预料,而且一旦发生在界面线程上,界面就不再刷新响和应用户输入;如果发生在后台线程,后台线程也就阻塞不工作了,死锁必然会导致应用程序不可用。在.NET里发生死锁的原因是什么?

以 C# 为例,通常 lock 语句是被转化为对一个资源的无限长时间的等待,所以一旦资源被占用而又永不释放,那么必然死锁。

那么如何规避的危害呢?应用程序应该避免 lock(obj) 块,推荐使用 Monitor.TryEnter(obj, millisecondsTimeout) 代替,二者的第一个参数意义相同,而后者还可以设置等待超时时间,一旦在限定的时间内无法获得锁,那么 TryEnter 就会返回  false。这样就不会造成死锁,无法获得资源,业务程序可以采取重试或抛异常的方式进行善后处理。

Monitor.TryEnter 和 Monitor.Exit 必须成对出现,为了简化代码,可以用一个实现IDisposeable的类来封装这个过程:

      /// <summary>
    /// 会自动释放的锁,可设置等待超时
    /// </summary>
    public class Lock : IDisposable
    {
        /// <summary>
        /// 默认超时设置
        /// </summary>
        public static int DefaultMillisecondsTimeout = 15000; // 15S
        private object _obj;

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="obj">想要锁住的对象</param>
        public Lock(object obj)
        {
            TryGet(obj, DefaultMillisecondsTimeout, true);
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="obj">想要锁住的对象</param>
        /// <param name="millisecondsTimeout">超时设置</param>
        public Lock(object obj, int millisecondsTimeout)
        {
            TryGet(obj, millisecondsTimeout, true);
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="obj">想要锁住的对象</param>
        /// <param name="millisecondsTimeout">超时设置</param>
        /// <param name="throwTimeoutException">是否抛出超时异常</param>
        public Lock(object obj, int millisecondsTimeout, bool throwTimeoutException)
        {
            TryGet(obj, millisecondsTimeout, throwTimeoutException);
        }

        private void TryGet(object obj, int millisecondsTimeout, bool throwTimeoutException)
        {
            if (Monitor.TryEnter(obj, millisecondsTimeout))
            {
                _obj = obj;
            }
            else
            {
                if (throwTimeoutException)
                {
                    throw new TimeoutException();
                }
            }
        }

        /// <summary>
        /// 销毁,并释放锁
        /// </summary>
        public void Dispose()
        {
            if (_obj != null)
            {
                Monitor.Exit(_obj);
            }
        }

        /// <summary>
        /// 获取在获取锁时是否发生等待超时
        /// </summary>
        public bool IsTimeout
        {
            get
            {
                return _obj == null;
            }
        }
    }

调用例子:

using (Lock l = new Lock(obj, 10000))
{
    ....
}

这样在代码离开 using 块后,会自动执行 Monitor.Exit释放锁。

是不是很棒? :)

同步基元-监视器Monitor的TryEnter方法应用 Monitor的TryEnter方法,不管获得或没获得锁都会立既返回False,如果得到锁就返回True,它不必像Enter方法那样没有得到锁就等待。 所以通过这个特征我们可以指示线程在获得锁的情况下执行一个操作,在没有获得锁的情况下执行另一个操作。   运行下面的例子,你会发现最终只有一个线程进行了操作。第一个进入锁定代码块的线程开始操作时,另一个线程过来访问锁定代码块时发现已被锁定,就会 阅读详情

相关推荐

C#多线程同步利器:Monitor全解析

摘要: C#的Monitor是多线程同步的核心工具,通过Enter/Exit实现互斥锁,确保共享资源安全访问,避免数据错乱。其高级功能Wait/Pulse可实现线程协作,典型应用如生产者-消费者模型,通过条件等待和唤醒机制提升效率。关键用法包括: 基础锁:Monitor.Enter+Exit(推荐用lock语法糖); 灵活尝试:TryEnter支持超时控制,避免阻塞; 线程协作:Wait释放锁并等待,Pulse唤醒等待线程,需配合while循环防虚假唤醒。 适用于共享资源操作和复杂线程协调场景,是构建稳健多

qq_34552942的博客 1157

C#多线程Monitor类锁定资源Monitor.TryEnter()的用法。通过一个例子告诉你什么是死锁。和解决方案

Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)) 该方法是检查锁对象在指定时间内是否释放资源,如果释放则返回true否则false 下面是死锁的例子:(大家复制到自己VS中跑一下,我给的是完整控制台代码,打断点调试一下,结合着我的注释,写的很详细。应该会理解的。) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System

csdn2990的博客 2270

C#面试题及详细答案120道(61-75)-- 多线程与异步

本文摘要了前后端面试题中关于线程与并发的核心知识点,包括线程与进程的区别(61题)、Thread/ThreadPool/Task的对比(62题)、线程安全实现方法(63题)、lock关键字的原理(64题)、Monitor类的进阶用法(65题)以及死锁的成因与避免(66题)。通过C#代码示例和表格对比,清晰展示了多线程编程的关键概念、应用场景及常见问题解决方案,适合开发者快速掌握面试高频考点。完整内容可访问专栏目录获取更多技术面试题解析。

大剑师兰特的GIS世界 1429

c# Monitor

Monitor主要方法TryEnter、Enter、Exit lock关键字基于Monitor.Enter,Monitor.Exit 实现 static void Main(string[] args) { for (int j = 0; j < 10; j++) { int k = j; Task.Run(() =>

czjnoe的博客 1659

工控上位机跑几天就莫名崩溃?8大高频根因盘点与C#工程化排查方案

做工控上位机开发这些年,见过最磨人的问题不是编译报错,也不是现场连不上设备,而是“跑几天就崩”——刚上线前两天一切正常,第三天凌晨莫名退出,重启后又能跑几天,日志里要么空空如也,要么只有一堆无关信息,查问题如同大海捞针。很多新手遇到这种情况第一反应是“电脑中毒了”“系统不稳定”,实际上90%以上都是代码里的累积型问题。即时Bug一跑就出,好定位;但资源泄漏、线程堆积、异常逃逸这类问题,需要时间累积到阈值才会爆发,所以才会“跑几天才崩”。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 253

2023-ICCV-隐式神经网络实现低光照图像增强(NeRCo)论文解读+代码解析

NeRCo()提出了一种名为NeRCo的隐式神经表示方法,用于合作式低光图像增强。现有的低光图像增强方法存在以下三个限制:不可预测的亮度降低和噪声、度量友好版本和视觉友好版本之间的固有差距,以及有限的配对训练数据。为了解决这些限制,论文提出了NeRCo方法,它以无监督的方式稳健地恢复感知友好的结果。具体而言,NeRCo通过一个可控的拟合函数统一了现实场景中多样的退化因素,从而提高了鲁棒性。对于输出结果,论文引入了来自预训练视觉-语言模型的先验信息,采用语义导向的监督方法。

weixin_45595504的博客 3184

C# 利用 Monitor.TryEnter 来规避 .NET 线程死锁的源代码

利用 Monitor.TryEnter 来规避 .NET 线程死锁的源代码

a876106354的博客 478

MOSFET高频响应实战:如何用LTspice仿真内部电容效应(附模型文件)

本文深入解析MOSFET高频响应中的内部电容效应,通过LTspice仿真工具详细展示如何提取模型参数并优化高频特性。从栅极相关电容到结电容的物理本质,再到实战案例中的开关损耗分析和频率响应扫描,提供全面的设计优化方法,帮助工程师有效应对高速开关电路中的电容挑战。

weixin_33725722的博客 390

利用 Monitor.TryEnter 来规避 .NET 线程死锁

在开发多线程的应用程序时,我们会大量用到 lock (...) {} 块。如果 lock 的对象比较多,非常容易发生死锁。死锁的发生很难预料,而且一旦发生在界面线程上,界面就不再刷新响和应用户输入;如果发生在后台线程,后台线程也就阻塞不工作了,死锁必然会导致应用程序不可用。在.NET里发生死锁的原因是什么?以 C# 为例,通常 lock 语句是被转化为对一个资源的无限长时间的等待,所以一旦资源

DocSun的专栏 1679

STM32智能头盔DIY全攻略:从心率监测到跌倒报警的完整实现

本文提供了基于STM32的智能头盔完整DIY实现方案,涵盖从心率监测到跌倒报警的核心功能。详细解析了系统设计、硬件搭建、软件算法及系统联调,重点介绍了STM32主控、MAX30102心率传感器和MPU6050姿态传感器的应用,并分享了跌倒检测算法与功耗优化等实战经验,为嵌入式开发与物联网创新项目提供全面指导。

sony5的博客 498

别再手动下单了!用Python+EasyTrader+同花顺,5分钟搞定你的第一个自动化交易机器人

本文详细介绍了如何使用Python和EasyTrader结合同花顺客户端快速构建自动化交易机器人。从环境配置到实战脚本编写,涵盖自动打新、条件单、跟单策略等核心功能,并分享性能优化与风险控制技巧,帮助投资者高效实现自动化交易。

weixin_30381317的博客 398

C# 多线程|线程优先级+委托传参+线程锁+死锁

死锁:两个及以上线程,互相持有对方需要的锁资源,互相阻塞等待,双方都不释放资源,线程永久卡死,程序无响应通俗类比:张三拿A钥匙要B钥匙;李四拿B钥匙要A钥匙,两人僵持不动。

2501_91389120的博客 547

RAG面试内容整理-8. 文档分块策略(滑动窗口、语义切分)

RAG系统通常面对长文档或整篇知识库资料的检索需求,但大模型一次处理的文本长度有限,向量索引也需固定大小的文本片段。因此,将长文档拆分成合适片段是必不可少的步骤,被称为文档分块(chunking)策略。

不务正业的猿 690

WPF多线程UI安全更新:11个实战Demo讲透Dispatcher.Invoke原理

WPF多线程编程的核心挑战在于UI线程模型与后台执行的天然隔离——所有控件访问必须发生在创建它的Dispatcher线程上。其底层原理基于消息泵机制与同步上下文(SynchronizationContext)的绑定,技术价值在于保障界面响应性与数据一致性。典型应用场景包括后台任务进度更新、异步数据加载、定时器刷新及用户交互决策回传等。在遗留系统维护、MES/ERP桌面端升级、WinForms迁移WPF等工程实践中,`Dispatcher.Invoke`与`Dispatcher.InvokeAsync`仍是不

didi9310的博客 403

MobileFusion:基于结构重参数化的移动端红外可见光图像融合方法

MobileFusion提出了一种轻量化的红外与可见光图像融合框架,通过结构重参数化技术实现移动端实时部署。该方法包含可重参数多分支卷积(RepMBConv)、轻量化上下文感知注意力(LCAA)和重参数前馈网络(RepFFN)三大模块,在训练时保留多分支结构增强特征学习,推理时合并为单路算子提升效率。实验表明,MobileFusion在MSRS、FMB等数据集上实现了融合质量与推理速度的平衡,参数量仅4000,在边缘设备上也能高效运行,为资源受限场景提供了实用解决方案。代码已开源。

毕竟是Shy哥 137

零基础做AI漫剧:Kimi K2.5写本 + Flux生图 + Seedance 2.0动效的保姆级教程

很多零基础小伙伴想做AI漫剧,却被“写剧本、画分镜、做动效”三大难题劝退——不会写剧情、不会画插画、不会做动态,觉得门槛太高。其实不用慌!今天就给大家带来保姆级教程,全程用Kimi K2.5(写剧本)、Flux(生分镜图)、Seedance 2.0(做动效)三个工具,不用专业技能,不用手动绘画,零基础也能在1小时内做出1分钟完整AI漫剧,全程步骤拆解、示例齐全,跟着做就能出片!

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 3033

C# Timer深度解析:从三大类型对比到实战避坑指南

在C#编程中,定时器是实现异步任务调度和周期性执行的核心组件。其原理基于线程池回调机制,通过在指定时间间隔触发事件来执行后台任务,为应用程序提供了异步处理能力。这一技术价值在于能够有效管理后台作业,提升程序响应性,避免阻塞主线程。常见的应用场景包括数据同步、UI定时刷新、心跳包发送和日志清理等后台服务。然而,若使用不当,开发者极易陷入并发执行、异常吞噬、资源管理混乱等陷阱。本文聚焦于System.Timers.Timer,深入剖析其在高并发场景下的线程安全问题,并提供构建健壮任务执行器的实战方案,帮助开发者

cuml0912的博客 557

YOLOv11改进策略【注意力机制篇】| SE、CBAM、ECA、CA、Swin Transformer等注意力机制全面解析与应用

本文详细介绍了五种主流的注意力机制及其在YOLOv11中的应用。通过合理的模块选择和位置部署,注意力机制能够显著提升目标检测性能。

QQ_778132974的博客 873

C# 锁机制——【2】深入原理

文章介绍了.NET锁优化机制:CLR通过对象头实现薄锁/厚锁状态机,JIT内联快速路径并自适应自旋;CAS操作须用SpinWait退避防止总线风暴;高竞争下会出现锁车队效应,需合理使用lock和自旋。

leonkay的博客 403

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Monitor.TryEnter使用避坑

使用对象,而非简单变量

WLB 的博客 1145

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

C# 线程手册 第三章 使用线程 Monitor.TryEnter()

Monitor 类的TryEnter() 方法在尝试获取一个对象上的显式锁方面和 Enter() 方法类似。然而,它不像Enter()方法那样会阻塞执行。如果线程成功进入关键区域那么TryEnter()方法会返回true. TryEnter()方法的三个重载方法中的两个以一个timeout类型值作为参数,表示按照指定时间等待锁。我们来看一个关于如何使用TryEnter()方法的例子,Monito...

weixin_33923762的博客 416

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Monitor.TryEnter方法和lock语句

其实两者的功能都是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。Monitor.TryEnter方法就是获取对象的排它锁是否成功(方法具体版本可以参考MSDN);lock语句就是Monitor.Enter和Monitor.Exit的封装。MSDN里描述Monitor.TryEnter无论有没有获取对象锁都会返回结果,而Lock会在外面等直到占用的线程退出下一个线程才能进去。首先用代码测

学习设计与编程 1152

并发编程 - 线程同步(七)之互斥锁Monitor

学习C#互斥锁Monitor,注意避免锁定值类型和try/finally错误,善用TryEnter避免长时间持锁,以及使用Wait、Pulse等方法实现生产者-消费者模式。示例代码和测试方法在代码库。

IT规划师 1127
上一篇: 近期 IE 打开新浪搜狐网页 CPU 使用率高的解决方法
下一篇: 最近用VS2005C#开发的IE内核多页签浏览器,支持多线程下载和在后台保存MHT
AppFramework
博客等级 码龄19年 61粉丝 29原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值