Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >NET中的线程锁

NET中的线程锁

作者头像
郑子铭
发布于 2025-03-24 07:05:02
发布于 2025-03-24 07:05:02
12600
代码可运行
举报
运行总次数:0
代码可运行

在.NET中,线程锁(Thread Locking)是一种重要的同步机制,用于确保多个线程在访问共享资源时不会发生冲突,保证线程安全。线程锁的核心目标是避免数据竞争和不一致的状态,确保在同一时刻只有一个线程能够访问特定的资源或代码块。本文将详细讲解.NET中的线程锁,帮助你理解其工作原理、常见实现方式及注意事项。

常见的线程锁有:

  • • 自旋锁:当线程尝试获取锁时,它会重复执行一些简单的指令,直到锁可用
  • • 互斥锁: Mutex,可以跨进程使用。Mutex 类定义了一个互斥体对象,可以使用 WaitOne() 方法等待对象上的锁
  • • 混合锁:Monitor,可以通过 lock 关键字来使用
  • • 读写锁:允许多个线程同时读取共享资源,但只允许单个线程写入共享资源
  • • 信号量:Semaphore,它允许多个线程同时访问同一个资源 来源:Z7TS

1. 为什么需要线程锁?

在多线程编程中,多个线程可能同时访问共享资源(如变量、文件、数据库等)。如果多个线程在没有同步机制的情况下同时访问同一资源,可能会导致以下问题:

  • 数据竞争:不同线程同时修改相同数据,导致数据不一致。
  • 竞态条件:由于线程的执行顺序不可预测,可能会出现不正确的结果。

为了避免这些问题,我们需要使用线程锁来控制对共享资源的访问,确保每次只有一个线程能访问临界区(Critical Section)。

2. .NET 中线程锁的实现方式

在.NET中,线程锁的实现方式主要有以下几种:

(1) lock 关键字

lock 是.NET中最常用的线程锁机制。它是 Monitor.EnterMonitor.Exit 的简化封装。通过使用 lock,你可以锁定一个对象,确保同一时刻只有一个线程能够进入被锁定的代码块。

使用方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    privatestaticreadonlyobject lockObject = newobject();

    static void Main()
    {
        Thread t1 = new Thread(Method);
        Thread t2 = new Thread(Method);

        t1.Start();
        t2.Start();
    }

    static void Method()
    {
        // 使用 lock 锁定临界区
        lock (lockObject)
        {
            Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 正在执行");
            Thread.Sleep(1000);  // 模拟耗时操作
        }
    }
}

在此例中,lock 关键字会锁定 lockObject 对象,使得 Method 方法内的代码在任意时刻只能被一个线程执行。

(2) Monitor

Monitor 类是 .NET 提供的低级别同步工具,lock 背后就是基于 Monitor 的实现。Monitor 提供了更精细的控制,可以手动获取和释放锁。

使用方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    privatestaticreadonlyobject lockObject = newobject();

    static void Main()
    {
        Thread t1 = new Thread(Method);
        Thread t2 = new Thread(Method);

        t1.Start();
        t2.Start();
    }

    static void Method()
    {
        Monitor.Enter(lockObject);  // 显式获取锁

        try
        {
            Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 正在执行");
            Thread.Sleep(1000);  // 模拟耗时操作
        }
        finally
        {
            Monitor.Exit(lockObject);  // 确保释放锁
        }
    }
}

在这个例子中,Monitor.Enter 手动获取锁,Monitor.Exit 释放锁。使用 try-finally 确保即使发生异常,也能释放锁。

(3) Mutex

Mutex 是一种更为强大的锁机制,通常用于不同进程之间的同步。它不仅支持跨线程同步,还支持跨进程同步。与 lockMonitor 只限于线程级别的同步不同,Mutex 主要用于操作系统级别的锁。

使用方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    privatestatic Mutex mutex = new Mutex();

    static void Main()
    {
        Thread t1 = new Thread(Method);
        Thread t2 = new Thread(Method);

        t1.Start();
        t2.Start();
    }

    static void Method()
    {
        mutex.WaitOne();  // 获取 Mutex 锁

        try
        {
            Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 正在执行");
            Thread.Sleep(1000);  // 模拟耗时操作
        }
        finally
        {
            mutex.ReleaseMutex();  // 释放 Mutex 锁
        }
    }
}

MutexWaitOne() 方法获取锁,ReleaseMutex() 方法释放锁。Mutex 的主要优势在于它可以用于跨进程同步,但性能上比 lockMonitor 更重。

(4) SemaphoreSemaphoreSlim

Semaphore 是一种允许多个线程同时访问某个资源的同步机制。它通过设置一个计数器来控制最多多少个线程可以同时访问一个特定资源。当计数器为零时,新的线程必须等待其他线程释放资源。

SemaphoreSlimSemaphore 的轻量级版本,适用于线程同步。

使用方法(SemaphoreSlim):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    privatestatic SemaphoreSlim semaphore = new SemaphoreSlim(2);  // 最大同时允许2个线程访问

    static void Main()
    {
        Thread t1 = new Thread(Method);
        Thread t2 = new Thread(Method);
        Thread t3 = new Thread(Method);

        t1.Start();
        t2.Start();
        t3.Start();
    }

    static void Method()
    {
        semaphore.Wait();  // 获取信号量

        try
        {
            Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 正在执行");
            Thread.Sleep(1000);  // 模拟耗时操作
        }
        finally
        {
            semaphore.Release();  // 释放信号量
        }
    }
}

这个例子中,最多允许 2 个线程同时执行 Method 方法。

3. 线程锁的注意事项

  1. 1. 死锁(Deadlock):死锁是指两个或多个线程互相等待对方释放锁,从而导致程序无法继续执行。避免死锁的策略包括:
    • • 按固定顺序获取锁。
    • • 使用 Monitor.TryEnter 来尝试获取锁,而不是无限期等待。
  2. 2. 性能问题:虽然线程锁能够确保线程安全,但不当使用可能会导致性能瓶颈,尤其是当锁的粒度较大时。尽量缩小锁的范围,并避免长时间持有锁。
  3. 3. 可重入性lockMonitor 都是可重入的,即同一个线程可以多次进入同一个锁定区域,而不会发生死锁。
  4. 4. 选择合适的锁类型:选择合适的锁类型非常重要。如果只是保护一个线程内部的资源,lock 是最简便的选择。如果涉及到多个进程之间的同步,Mutex 是更好的选择。

4. 总结

常用的锁机制包括 lock 关键字、Monitor 类、Mutex 类以及 Semaphore 等。线程锁的使用可以有效避免数据竞争和不一致的状态,但也需要谨慎使用,避免死锁、性能问题等。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# 锁机制全景与高效实践:从 Monitor 到 .NET 9 全新 Lock
在多线程编程中,保障共享资源的安全访问依赖于有效的线程同步机制。理解并处理好以下两个核心概念至关重要:
AI.NET 极客圈
2025/06/12
1150
C# 锁机制全景与高效实践:从 Monitor 到 .NET 9 全新 Lock
多线程中的锁系统(一)-基础用法
     平常在多线程开发中,总避免不了线程同步。本篇对net多线程中的锁系统做个简单描述。 阅读目录: lock、Monitor 作用域范围 字符串锁 Monitor的用法 Mutex Semaphore 总结 lock、Monitor Lock是Monitor语法糖简化写法,Lock在IL会生成Monitor。 //======Example 1===== string obj = "helloworld"; lock (obj)
蘑菇先生
2018/05/21
6440
C# 温故而知新: 线程篇(四)
线程同步篇 (中):同步工具类的介绍 1 上篇回顾 2 继续介绍基元内核模式中的 monitor类 3 同步句柄:WaitHandle 4 EventWaitHandle,AutoResetEvent和ManualResetEvent 5 同步互斥mutex类 6 简单说明下mutex和monitor的区别 7 选择我们需要的同步工具 8 本章总结   1 上篇回顾 很抱歉好久没写博客了,由于工作太忙,所以最近一段时间落下了,让我们开始上一篇向大家介绍了下线程同步中的一些重要概念包括
逸鹏
2018/04/10
9750
C# 温故而知新: 线程篇(四)
C#多线程锁「建议收藏」
C#开发中会常遇到多线程的问题,当多个线程同时对同一个资源进行操作时,就需要注意线程同步的问题。线程如果不同步,可能会造成与预计不同的结果,这时就要对资源进行上锁。当多个线程操作一个全局变量时,如果对全局变量进行上锁,则当一个线程访问这个全局变量时,另一个线程并不能去访问这个全局变量,只有等解锁资源后,其余线程才有机会去访问。这就保证了线程同步。下面是示例: 两个线程fun1和fun2同时对队列进行入队操作,当入队数量比较小时,可能没有问题,当数量较大时,会发现队列中元素个数并不是两个线程入队元素的和。
全栈程序员站长
2022/08/31
6270
C#学习笔记 线程同步
多个线程同时操作一个数据的话,可能会发生数据的错误。这个时候就需要进行线程同步了。线程同步可以使用多种方法来进行。下面来逐一说明。本文参考了《CLR via C#》中关于线程同步的很多内容。
乐百川
2022/05/05
6030
.NET简谈组件程序设计之(手动同步)
在上一篇文章“.NET简谈组件程序设计之(上下文与同步域) ”中,我们学习了关于一些上下文和同步域的概念,可以利用这两个技术来进行自动同步。
王清培
2022/03/14
2840
.NET简谈组件程序设计之(手动同步)
C#13中线程同步的作用域锁
C# 13 引入了新的功能,旨在让编码变得更简单、更高效。其中的一个亮点是通过 System.Threading.Lock 类引入的作用域锁功能。这让线程同步变得更加简单,并减少了多线程程序中的错误。
郑子铭
2025/02/18
960
C#13中线程同步的作用域锁
C# 多线程编程入门教程
随着硬件性能的提升,尤其是多核CPU的广泛应用,多线程编程已经成为现代软件开发中的核心技能之一。多线程可以让程序在多个核心上并发运行,提高效率和性能。然而,编写多线程程序并不是一件简单的事情,尤其是要处理线程间的同步问题,以避免数据竞争和死锁等问题。
Michel_Rolle
2024/09/23
3K0
【深入浅出C#】章节 9: C#高级主题:多线程编程和并发处理
多线程编程和并发处理的重要性和背景 在计算机科学领域,多线程编程和并发处理是一种关键技术,旨在充分利用现代计算机系统中的多核处理器和多任务能力。随着计算机硬件的发展,单一的中央处理单元(CPU)已经不再是主流,取而代之的是多核处理器,这使得同时执行多个任务成为可能。多线程编程允许开发人员将一个程序拆分成多个线程,这些线程可以并行执行,从而提高程序的性能和响应速度。 为什么多线程在现代应用中至关重要?
喵叔
2023/08/26
5.2K0
线程安全(ThreadSafety)
上节提到了线程安全的问题,说了一个例子,1000个人抢100张票,这节就从此案例着手,下面先看一下代码实现:
宿春磊Charles
2022/03/29
3900
线程安全(ThreadSafety)
C#多线程系列(2):多线程锁lock和Monitor
C# 中,可以使用 lock 关键字和 Monitor 类来解决多线程锁定资源和死锁的问题。
痴者工良
2021/04/26
4.6K0
.Net 中各种线程同步锁
编程编的久了,总会遇到多线程的情况,有些时候我们要几个线程合作完成某些功能,这时候可以定义一个全局对象,各个线程根据这个对象的状态来协同工作,这就是基本的线程同步。
tuoxie
2024/08/18
1910
.Net 中各种线程同步锁
C#的锁
在多线程编程中,确保线程安全是至关重要的。C#提供了多种锁机制来同步线程间的访问,以防止数据竞争和其他并发问题。本文将深入探讨C#中的锁,包括它们的基本概念、实现方式、高级用法和最佳实践。
Michel_Rolle
2024/10/08
3K0
并发编程 --- 信号量线程同步
实际上,再C#中 EventWaitHandle 、 Semaphore 、 Mutex 都是抽象类 WaitHandle 的派生类,它提供了一组等待信号的方法和属性。如下图:
Niuery Diary
2023/10/22
2120
并发编程 --- 信号量线程同步
C# Monitor
C#中的Monitor是一种多线程同步机制,它用于控制线程对共享资源的访问,通过提供独占锁、等待和通知机制,以及对值类型的支持,确保多线程程序的线程安全和协调执行,防止竞态条件和数据不一致性。
JusterZhu
2023/09/28
3440
C# Monitor
.NET面试题系列[18] - 多线程同步(1)
多个线程同时访问共享资源时,线程同步用于防止数据损坏或发生无法预知的结果。对于仅仅是读取或者多个线程不可能同时接触到数据的情况,则完全不需要进行同步。
s055523
2018/09/14
1.4K0
.NET面试题系列[18] - 多线程同步(1)
关于C#多线程、易失域、锁的分享
  windows系统是一个多线程的操作系统。一个程序至少有一个进程,一个进程至少有一个线程。进程是线程的容器,一个C#客户端程序开始于一个单独的线程,CLR(公共语言运行库)为该进程创建了一个线程,该线程称为主线程。例如当我们创建一个C#控制台程序,程序的入口是Main()函数,Main()函数是始于一个主线程的。它的功能主要 是产生新的线程和执行程序。
用户7053485
2020/03/12
1K0
c#之线程总结(一)
在我们做项目的时候会经常用到线程,但线程也不是万能的,用线程需要注意的东西也很多,自己做了一下总结 这次总结主要说三个部分 1 线程之委托方法 2 给线程传参 3 三种方法控制线程同步 我们先看一下小例子: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadMethod { class Progr
lpxxn
2018/01/31
4760
c#之线程总结(一)
C#多线程学习lock,Monitor,Mutex的区别
一、lock的底层本身是Monitor来实现的,所以Monitor可以实现lock的所有功能。 二、Monitor有TryEnter的功能,可以防止出现死锁的问题,lock没有。
zls365
2020/11/25
1.7K0
.NET基础拾遗(5)多线程开发基础
  下面的一些基本概念可能和.NET的联系并不大,但对于掌握.NET中的多线程开发来说却十分重要。我们在开始尝试多线程开发前,应该对这些基础知识有所掌握,并且能够在操作系统层面理解多线程的运行方式。
Edison Zhou
2018/08/20
8790
.NET基础拾遗(5)多线程开发基础
相关推荐
C# 锁机制全景与高效实践:从 Monitor 到 .NET 9 全新 Lock
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验