在 C# 多线程编程中,当多个线程访问共享资源时,可能会出现数据不一致或其他并发问题,这时就需要使用互斥机制来确保同一时间只有一个线程可以访问共享资源。以下是几种常见的 C# 多线程互斥方法:
lock
语句是 C# 中最常用的实现线程互斥的方式,它基于 Monitor
类实现,使用简单方便。
using System;
using System.Threading;
class Program
{
private static readonly object lockObject = new object();
private static int sharedResource = 0;
static void Main()
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine($"Shared resource value: {sharedResource}");
}
static void Increment()
{
for (int i = 0; i < 100000; i++)
{
lock (lockObject)
{
sharedResource++;
}
}
}
}
解释:
lockObject
是一个用于同步的对象,通常是一个私有静态的 object
类型实例。
lock
语句会获取 lockObject
的锁,如果锁已被其他线程持有,则当前线程会阻塞,直到锁被释放。
- 在
lock
语句块内的代码是临界区,同一时间只有一个线程可以执行该代码块,从而保证了对 sharedResource
的安全访问。
Monitor
类提供了更底层的线程同步机制,
lock
语句实际上是
Monitor
类的语法糖。
using System;
using System.Threading;
class Program
{
private static readonly object monitorObject = new object();
private static int sharedValue = 0;
static void Main()
{
Thread t1 = new Thread(UpdateValue);
Thread t2 = new Thread(UpdateValue);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine($"Shared value: {sharedValue}");
}
static void UpdateValue()
{
for (int i = 0; i < 100000; i++)
{
Monitor.Enter(monitorObject);
try
{
sharedValue++;
}
finally
{
Monitor.Exit(monitorObject);
}
}
}
}
解释:
Monitor.Enter
方法用于获取指定对象的锁,如果锁已被其他线程持有,则当前线程会阻塞。
try-finally
块确保无论是否发生异常,Monitor.Exit
方法都会被调用,从而释放锁。
Mutex
(互斥体)是一种跨进程的同步原语,可用于在多个进程或线程之间实现互斥访问。
using System;
using System.Threading;
class Program
{
private static readonly Mutex mutex = new Mutex();
private static int counter = 0;
static void Main()
{
Thread t1 = new Thread(Count);
Thread t2 = new Thread(Count);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine($"Counter value: {counter}");
}
static void Count()
{
for (int i = 0; i < 100000; i++)
{
mutex.WaitOne();
try
{
counter++;
}
finally
{
mutex.ReleaseMutex();
}
}
}
}
解释:
mutex.WaitOne
方法用于请求获取互斥体的所有权,如果互斥体已被其他线程或进程持有,则当前线程会阻塞。
mutex.ReleaseMutex
方法用于释放互斥体的所有权,允许其他线程或进程获取该互斥体。
SemaphoreSlim
是一个轻量级的信号量,可用于限制同时访问共享资源的线程数量。当将最大计数设置为 1 时,它可以作为互斥锁使用。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
private static int sharedData = 0;
static async Task Main()
{
Task t1 = Task.Run(UpdateData);
Task t2 = Task.Run(UpdateData);
await Task.WhenAll(t1, t2);
Console.WriteLine($"Shared data value: {sharedData}");
}
static async Task UpdateData()
{
for (int i = 0; i < 100000; i++)
{
await semaphore.WaitAsync();
try
{
sharedData++;
}
finally
{
semaphore.Release();
}
}
}
}
解释:
SemaphoreSlim
的构造函数第一个参数表示初始计数,第二个参数表示最大计数。当最大计数为 1 时,它就相当于一个互斥锁。
semaphore.WaitAsync
方法用于请求获取信号量,如果信号量计数为 0,则当前线程会等待。
semaphore.Release
方法用于释放信号量,将计数加 1。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)