当前位置:首页 > 技术知识 > 正文内容

C# 中的多线程同步机制:lock、Monitor 和 Mutex 用法详解

maynowei9个月前 (08-03)技术知识198

在多线程编程中,线程同步是确保多个线程安全地访问共享资源的关键技术。C# 提供了几种常用的同步机制,其中 lock、Monitor 和 Mutex 是最常用的同步工具。本文将全面介绍这三种同步机制的用法、优缺点以及适用场景,帮助开发者在多线程开发中做出合适的选择。

1. lock 关键字 1.1 概述 在 C# 中,lock 关键字是用于线程同步的最常用工具之一。lock 是 Monitor.Enter() 和 Monitor.Exit() 的语法糖,通过锁住一个共享资源来确保在同一时刻只有一个线程可以访问它。lock 适用于同一个进程中的线程同步,尤其是在多个线程访问共享数据时,能够有效地防止数据竞态和线程安全问题。

1.2 用法 lock 关键字的常见用法是围绕一个对象的引用,将其作为锁对象来同步线程。通常,lock 语句会包装一个临界区(共享资源访问区),当一个线程执行完临界区代码后,另一个线程才能进入临界区。 示例代码:

using System;

using System.Threading;

class Program

{

private static readonly object _lock = new object();

// 锁对象

static void Main()

{

Thread t1 = new Thread(DoWork);

Thread t2 = new Thread(DoWork);

t1.Start();

t2.Start();

}

static void DoWork()

{ lock (_lock) // 获取锁 { Console.WriteLine("线程进入临界区...");

Thread.Sleep(1000);

// 模拟处理时间 Console.WriteLine("线程离开临界区...");

}

}

}

说明: 在 lock (_lock) 中,_lock 是锁对象。lock 保证了在同一时刻只有一个线程可以进入 lock 语句块内部的代码。 lock 会在代码块执行完毕后自动释放锁,无需手动释放。 1.3 优缺点 优点: 语法简洁,易于理解和使用。 自动释放锁,减少了因为忘记释放锁而导致死锁的风险。 缺点: 只能用于同一个进程中的线程之间的同步,不能跨进程使用。 无法提供更多的同步控制,比如等待和通知机制。

2. Monitor 类 2.1 概述 Monitor 类是 C# 提供的底层同步机制,比 lock 更加灵活和精细。Monitor 提供了对锁的手动控制,允许你在获取锁后,等待其他线程的通知或条件满足才能继续执行。Monitor 适合那些需要更多同步控制的场景,比如等待和通知机制。 2.2 用法 Monitor 类提供了几个关键的方法: Enter(object obj):尝试获取锁,如果成功,线程继续执行。 Exit(object obj):释放锁,允许其他线程访问锁定的资源。 Wait(object obj):使当前线程等待,直到其他线程通知它。 Pulse(object obj):唤醒一个等待该锁的线程。 PulseAll(object obj):唤醒所有等待该锁的线程。 示例代码:

using System;

using System.Threading;

class Program

{

private static readonly object _lock = new object(); // 锁对象

static void Main()

{

Thread t1 = new Thread(DoWork);

Thread t2 = new Thread(DoWork);

t1.Start();

t2.Start();

}

static void DoWork()

{

Monitor.Enter(_lock);// 获取锁 try

{ Console.WriteLine("线程进入临界区...");

Thread.Sleep(1000);

// 模拟工作

Console.WriteLine("线程离开临界区...");

}

finally { Monitor.Exit(_lock);

// 确保释放锁 } } }

说明:

Monitor.Enter(_lock) 获取锁,Monitor.Exit(_lock) 释放锁。 Monitor 更加底层,提供了细粒度的控制,适用于复杂的同步场景。 使用 try/finally 语句确保即使在发生异常时,也能释放锁。 2.3 优缺点 优点: 比 lock 更灵活,支持等待和通知机制,如 Wait、Pulse 和 PulseAll。 适用于需要更多控制的同步场景。 缺点: 使用起来相对复杂,容易出错,尤其是在手动管理锁时。 只支持同一进程内的线程同步。

相关文章

Go语言进阶:时间轮(golang时间轮)

时间轮概念时间轮(Timing Wheel)是一种高效的定时任务调度数据结构,特别适合处理大量定时任务。它通过一个循环数组(轮盘)和多个槽位(buckets)来组织定时任务,每个槽位代表一个时间间隔。...

聊聊并发编程: Lock(并发锁有哪些)

之前学习了如何使用synchronized关键字来实现同步访问,Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功...

一个快要被忘记的数据库开发岗位,但应该被尊重

数据库测试,似乎是被人遗忘的数据库职业,但依然是不错的选择。底下是我在某站找的招聘启事,就连蚂蚁金服都在积极寻找数据库测试人:要说我经历的项目,大大小小也有几十个,从 C/S, B/S, 再到 B/C...

本地配置plsql远程连接oracle数据库

由于Oracle的庞大,有时候我们需要在只安装Oracle客户端如plsql、toad等的情况下去连接远程数据库,可是没有安装Oracle就没有一切的配置文件去支持。最后终于发现一个很有效的方法,O...

超详细的Oracle19c修改数据库用户名教程

概述由于开发很多视图指定了某个用户名,故需修改数据库用户名srmpro为srm。以下为操作过程..1、停止应用防止修改用户名密码后应用一直在发起错误连接,可事先查询哪个IP在连接数据库,然后断开对应连...

为什么说产品思维是用户体验设计的下一个趋势

加入人人都是产品经理【起点学院】产品经理实战训练营,BAT产品总监手把手带你学产品在思考用户体验的时候,我们经常想到的是集合了简单、美观、易用的功能的产品,这样会让用户的生活更容易。但事实上,功能仅仅...