一、场景
- 多线程环境中访问共享资源时,比如写入文件、修改共享变量等,使用
SemaphoreSlim
可以防止线程间的竞争条件和数据不一致问题。
二、异步写法
class Program
{
// 创建一个 SemaphoreSlim 实例,最大并发数为 1,确保同一时间只有一个线程可以写入文件
private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
static async Task Main(string[] args)
{
// 创建并启动异步任务,模拟多线程写入
var task1 = Task.Run(async() =>
{
for (int i = 0; i < 10; i++)
{
var res = $"线程1第{i}次写入";
await WriteToFileAsync(res);
}
}
);
var task2 = Task.Run(async () => {
for (int i = 0; i < 10; i++)
{
var res = $"线程2第{i}次写入";
await WriteToFileAsync(res);
}
});
// 等待所有任务完成
await Task.WhenAll(task1, task2);
Console.WriteLine("所有任务已完成");
}
// 异步向文件写入数据的方法
static async Task WriteToFileAsync(string data)
{
// 使用 SemaphoreSlim 控制并发访问
await semaphore.WaitAsync();//【A】
try
{
using (StreamWriter writer = new StreamWriter("data.txt", true))
{
await writer.WriteLineAsync($"{DateTime.Now}: {data}");
Console.WriteLine(data);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// 释放锁,允许其他线程访问
semaphore.Release();//【B】
}
}
}
若注释掉代码行【A】和【B】,将会出现线程冲突问题,因此,必须使用锁机制(例如 lock、SemaphoreSlim 等)来确保文件在同一时刻只能由一个线程访问
三、同步写法
改一下异步的写法即可:
1.去掉await async等关键字
2.await semaphore.WaitAsync() => semaphore.Wait()