0

0

c# 如何编写可重入的(Reentrant)和线程安全的代码

月夜之吻

月夜之吻

发布时间:2026-01-16 11:15:08

|

348人浏览过

|

来源于php中文网

原创

可重入指同一线程可多次调用未完成函数而不破坏状态;线程安全指多线程并发访问共享资源时不出现数据竞争。二者不等价:可重入关注单线程重入能力,线程安全关注多线程并发保护。

c# 如何编写可重入的(reentrant)和线程安全的代码

什么是可重入(Reentrant)和线程安全?先分清这两个概念

可重入 ≠ 线程安全,但二者常被混用。可重入指:**同一函数/方法在未执行完时,能被同一线程再次调用且不破坏内部状态**;典型场景是信号处理、递归调用或回调嵌套。lock 会阻塞同一线程再次进入(除非用 RecursiveLockMonitor.TryEnter 配超时),所以普通 lock 块默认不可重入。

线程安全则关注**多线程并发访问共享资源时不出现数据竞争或状态不一致**。它不要求可重入——比如一个只读的静态缓存可能线程安全但无需支持重入。

在 C# 中,真正同时满足“可重入 + 线程安全”的常见做法是:用 Monitor 手动控制重入计数,或改用 AsyncLocal<t></t> / 不可变对象 / 纯函数式设计来规避共享状态。

Monitor 实现可重入锁(ReentrantLock)

C# 的 lock 语句底层就是 Monitor.Enter/Exit,但它不暴露重入计数。要自己实现可重入行为,必须用 Monitor.TryEnter(obj, timeout) 并手动维护线程 ID 与进入次数映射。

注意:Monitor 本身是可重入的(.NET 运行时保证同一线程多次 Enter 不死锁),但你得确保每次 Exit 次数匹配,否则其他线程永远等不到释放。

《PHP设计模式指南》中文版
《PHP设计模式指南》中文版

《PHP设计模式》首先介绍了设计模式,讲述了设计模式的使用及重要性,并且详细说明了应用设计模式的场合。接下来,本书通过代码示例介绍了许多设计模式。最后,本书通过全面深入的案例分析说明了如何使用设计模式来计划新的应用程序,如何采用PHP语言编写这些模式,以及如何使用书中介绍的设计模式修正和重构已有的代码块。作者采用专业的、便于使用的格式来介绍相关的概念,自学成才的编程人员与经过更多正规培训的编程人员

下载
  • Monitor.EnterMonitor.Exit 必须成对出现在同一个线程中;异常时需 try/finally 保障 Exit
  • 不要跨线程调用 Monitor.Exit,会抛 SynchronizationLockException
  • 避免在锁内调用未知第三方代码(可能引发重入或死锁)
public class ReentrantLock
{
    private readonly object _syncRoot = new object();
    private Thread? _owner;
    private int _entryCount;
<pre class='brush:php;toolbar:false;'>public void Enter()
{
    var current = Thread.CurrentThread;
    lock (_syncRoot)
    {
        if (_owner == current)
        {
            _entryCount++;
            return;
        }
        Monitor.Enter(_syncRoot); // 等待获取锁
        _owner = current;
        _entryCount = 1;
    }
}

public void Exit()
{
    lock (_syncRoot)
    {
        if (Thread.CurrentThread != _owner)
            throw new InvalidOperationException("Exit called from non-owner thread");

        if (--_entryCount == 0)
        {
            _owner = null;
            Monitor.Exit(_syncRoot);
        }
    }
}

}

更轻量、更现代的替代方案:避免锁,用 AsyncLocal<t></t> 或不可变状态

如果你的“可重入”需求本质是想让递归调用或异步嵌套保持上下文隔离(比如日志追踪 ID、事务作用域),AsyncLocal<t></t> 是比手写可重入锁更安全、更符合 .NET 设计哲学的选择。

它自动随 async/await 流动,且每个逻辑执行路径拥有独立副本,天然线程安全、天然可重入——因为根本不共享状态。

  • AsyncLocal<t></t> 不适用于跨线程同步共享数据,只用于“逻辑上下文传播”
  • 若需共享可变状态,优先考虑 ImmutableArray<t></t> + Interlocked 更新引用,而非加锁
  • 纯函数式风格(无副作用、输入决定输出)天然可重入且线程安全,适合配置解析、DTO 转换等场景
private static readonly AsyncLocal<string> _traceId = new AsyncLocal<string>();
<p>public void DoWork(string id)
{
_traceId.Value = id; // 当前逻辑流独享
NestedCall();
}</p><p>private void NestedCall()
{
Console.WriteLine($"Current trace: {_traceId.Value}"); // 自动继承,不污染其他分支
}

容易踩的坑:别把 lock(this)lock(typeof(T)) 当可重入锁用

这些写法不仅不可重入,还极易引发死锁或意外锁竞争:

  • lock(this) 暴露了实例锁,外部代码也能锁它,导致协作失控
  • lock(typeof(T)) 是全 AppDomain/Assembly 级别锁,多个类库可能无意中锁住同一 Type 对象
  • Monitor.Enter(obj) 后没配对 Monitor.Exit(obj) —— 尤其在异常分支遗漏 finally,会导致永久挂起
  • async 方法里用 lock:await 会切出线程,再回来时可能已不是原线程,Monitor 不允许跨线程 Exit

真正的难点不在“怎么写锁”,而在于判断“是否真的需要锁”。多数业务逻辑的可重入需求,其实源于状态管理混乱——把上下文塞进静态字段、单例属性,才被迫去解决线程安全问题。重构掉共享可变状态,往往比写一个完美的 ReentrantLock 更有效。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

723

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

372

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

27

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

26

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

102

2026.02.06

JavaScript中的typeof用法
JavaScript中的typeof用法

在JavaScript中,typeof是一个用来确定给定变量的数据类型的操作符。可以用来确定一个变量是字符串、数字、布尔值、函数、对象或undefined的数据类型。更多关于typeof用法相关文章,详情请看本专题下面的文章,php中文网欢迎大家前来学习。

769

2023.11.23

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

2

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

5

2026.03.03

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

66

2026.02.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 75.9万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号