更详细的 C# 示例 Demo,扩展了之前的实现,涵盖多线程、多实例场景下的同步锁、异步锁、读写锁、分布式锁,并增加了更复杂的业务逻辑、性能监控、错误处理和死锁预防机制
更详细的 C# 示例 Demo,扩展了之前的实现,涵盖多线程、多实例场景下的同步锁、异步锁、读写锁、分布式锁,并增加了更复杂的业务逻辑、性能监控、错误处理和死锁预防机制。代码模拟了一个更真实的硬件管理场景,包含日志记录、资源清理、并发测试和分布式环境支持。所有内容用中文详细注释,确保清晰易懂。
Demo 目标
-
场景:模拟一个硬件管理系统,管理多个硬件端口(如 COM1, COM2),支持多线程、多实例并发访问,包含读写操作和跨进程的分布式锁。
-
功能:
-
实现同步锁(lock)、异步锁(SemaphoreSlim)、读写锁(ReaderWriterLockSlim)、分布式锁(Redis)。
-
支持多实例(实例级和静态级锁)。
-
模拟复杂业务逻辑(如读/写硬件、初始化、清理)。
-
集成性能监控(锁等待时间、并发统计)。
-
提供死锁预防(锁顺序、超时、避免嵌套)。
-
包含错误处理和日志记录。
-
-
环境:C# .NET 8,需安装 StackExchange.Redis NuGet 包用于分布式锁,Redis 服务器运行在 localhost:6379。
-
输出:详细日志,展示线程、实例、锁类型和操作结果。
示例代码
1. 公共组件
定义日志和性能监控工具类,用于记录操作和统计锁等待时间。
csharp
using System;
using System.Diagnostics;
using System.Threading;
public static class Logger
{
private static readonly object logLock = new object();
public static void Log(string message)
{
lock (logLock)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] {message}");
}
}
}
public class PerformanceTracker
{
private static long totalWaitTimeMs = 0;
private static int lockAttempts = 0;
public static void RecordWaitTime(long waitTimeMs)
{
Interlocked.Add(ref totalWaitTimeMs, waitTimeMs);
Interlocked.Increment(ref lockAttempts);
}
public static void PrintStats()
{
Logger.Log($"性能统计: 总锁等待时间 = {totalWaitTimeMs}ms, 平均等待时间 = {(lockAttempts > 0 ? totalWaitTimeMs / lockAttempts : 0)}ms, 锁尝试次数 = {lockAttempts}");
}
}
说明:
-
Logger:线程安全的日志记录,确保输出不乱序。
-
PerformanceTracker:记录锁等待时间,统计并发性能。
2. 同步锁(细粒度锁)
实现基于 lock 的细粒度锁,支持实例级隔离。
csharp
using System;
using System.Collections.Concurrent;
using System.Threading;
public class HardwareManagerSync
{
private readonly ConcurrentDictionary<string, object> HardwareLocks = new ConcurrentDictionary<string, object>();
private readonly string instanceId = Guid.NewGuid().ToString();
public void AccessHardware(string comPort, string operation)
{
var lockObject = HardwareLocks.GetOrAdd(comPort, _ => new object());
var stopwatch = Stopwatch.StartNew();
Logger.Log($"[Sync][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {comPort} 锁 ({operation})");
lock (lockObject)
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[Sync][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {comPort} 锁,执行 {operation}...");
// 模拟硬件操作
Thread.Sleep(operation == "read" ? 500 : 1000);
Logger.Log($"[Sync][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {comPort} 的 {operation}");
}
}
public void AccessTwoPorts(string comPort1, string comPort2, string operation)
{
// 按字母顺序获取锁,避免死锁
var ports = new[] { comPort1, comPort2 }.OrderBy(p => p).ToArray();
var lock1 = HardwareLocks.GetOrAdd(ports[0], _ => new object());
var lock2 = HardwareLocks.GetOrAdd(ports[1], _ => new object());
var stopwatch = Stopwatch.StartNew();
Logger.Log($"[Sync][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {ports[0]} 和 {ports[1]} 锁 ({operation})");
lock (lock1)
{
lock (lock2)
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[Sync][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {ports[0]} 和 {ports[1]} 锁,执行 {operation}...");
Thread.Sleep(operation == "read" ? 500 : 1000);
Logger.Log($"[Sync][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {ports[0]} 和 {ports[1]} 的 {operation}");
}
}
}
}
说明:
-
实例级锁:每个 HardwareManagerSync 实例有独立的 HardwareLocks。
-
死锁预防:AccessTwoPorts 按端口名称排序获取锁。
-
性能监控:记录锁等待时间。
-
业务逻辑:支持读(500ms)和写(1000ms)操作。
3. 异步锁(使用 SemaphoreSlim)
实现基于 SemaphoreSlim 的异步锁,支持非阻塞并发。
csharp
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class HardwareManagerAsync
{
private static readonly ConcurrentDictionary<string, SemaphoreSlim> HardwareLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
private readonly string instanceId = Guid.NewGuid().ToString();
static HardwareManagerAsync()
{
// 预分配锁对象
string[] comPorts = { "COM1", "COM2", "COM3" };
foreach (var port in comPorts)
{
HardwareLocks.TryAdd(port, new SemaphoreSlim(1, 1));
}
}
public async Task AccessHardwareAsync(string comPort, string operation)
{
var semaphore = HardwareLocks.GetOrAdd(comPort, _ => new SemaphoreSlim(1, 1));
var stopwatch = Stopwatch.StartNew();
Logger.Log($"[Async][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {comPort} 锁 ({operation})");
if (!await semaphore.WaitAsync(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException($"[Async][Instance {instanceId}] 无法获取 {comPort} 锁,操作 {operation}");
}
try
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[Async][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {comPort} 锁,执行 {operation}...");
await Task.Delay(operation == "read" ? 500 : 1000);
Logger.Log($"[Async][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {comPort} 的 {operation}");
}
finally
{
semaphore.Release();
}
}
public async Task AccessTwoPortsAsync(string comPort1, string comPort2, string operation)
{
var ports = new[] { comPort1, comPort2 }.OrderBy(p => p).ToArray();
var semaphore1 = HardwareLocks.GetOrAdd(ports[0], _ => new SemaphoreSlim(1, 1));
var semaphore2 = HardwareLocks.GetOrAdd(ports[1], _ => new SemaphoreSlim(1, 1));
var stopwatch = Stopwatch.StartNew();
Logger.Log($"[Async][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {ports[0]} 和 {ports[1]} 锁 ({operation})");
if (!await semaphore1.WaitAsync(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException($"[Async][Instance {instanceId}] 无法获取 {ports[0]} 锁");
}
try
{
if (!await semaphore2.WaitAsync(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException($"[Async][Instance {instanceId}] 无法获取 {ports[1]} 锁");
}
try
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[Async][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {ports[0]} 和 {ports[1]} 锁,执行 {operation}...");
await Task.Delay(operation == "read" ? 500 : 1000);
Logger.Log($"[Async][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {ports[0]} 和 {ports[1]} 的 {operation}");
}
finally
{
semaphore2.Release();
}
}
finally
{
semaphore1.Release();
}
}
public void Cleanup()
{
foreach (var pair in HardwareLocks)
{
if (HardwareLocks.TryRemove(pair.Key, out var semaphore))
{
semaphore.Dispose();
}
}
}
}
说明:
-
异步锁:SemaphoreSlim 支持非阻塞等待。
-
死锁预防:按端口名称排序,5秒超时。
-
资源清理:Cleanup 方法释放 SemaphoreSlim。
-
性能监控:记录锁等待时间。
-
静态锁字典:所有实例共享锁,适合类级资源。
4. 读写锁(使用 ReaderWriterLockSlim)
实现读写分离,支持多读单写。
csharp
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class HardwareManagerReadWrite
{
private static readonly ConcurrentDictionary<string, ReaderWriterLockSlim> HardwareLocks = new ConcurrentDictionary<string, ReaderWriterLockSlim>();
private readonly string instanceId = Guid.NewGuid().ToString();
static HardwareManagerReadWrite()
{
// 预分配锁对象
string[] comPorts = { "COM1", "COM2", "COM3" };
foreach (var port in comPorts)
{
HardwareLocks.TryAdd(port, new ReaderWriterLockSlim());
}
}
public async Task ReadHardwareAsync(string comPort)
{
var rwLock = HardwareLocks.GetOrAdd(comPort, _ => new ReaderWriterLockSlim());
var stopwatch = Stopwatch.StartNew();
Logger.Log($"[ReadWrite][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {comPort} 读锁");
rwLock.EnterReadLock();
try
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[ReadWrite][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {comPort} 读锁,执行读取...");
await Task.Delay(500);
Logger.Log($"[ReadWrite][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {comPort} 的读取");
}
finally
{
rwLock.ExitReadLock();
}
}
public async Task WriteHardwareAsync(string comPort)
{
var rwLock = HardwareLocks.GetOrAdd(comPort, _ => new ReaderWriterLockSlim());
var stopwatch = Stopwatch.StartNew();
Logger.Log($"[ReadWrite][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {comPort} 写锁");
if (rwLock.TryEnterWriteLock(TimeSpan.FromSeconds(5)))
{
try
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[ReadWrite][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {comPort} 写锁,执行写入...");
await Task.Delay(1000);
Logger.Log($"[ReadWrite][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {comPort} 的写入");
}
finally
{
rwLock.ExitWriteLock();
}
}
else
{
throw new TimeoutException($"[ReadWrite][Instance {instanceId}] 无法获取 {comPort} 写锁");
}
}
}
说明:
-
读写分离:允许多个读操作并行,写操作独占。
-
死锁预防:写锁设置超时,避免无限等待。
-
性能优化:读多写少场景下高效。
-
静态锁字典:共享锁对象,适合全局资源。
5. 分布式锁(使用 Redis)
实现基于 Redis 的分布式锁,支持跨进程/机器同步。
csharp
using System;
using System.Threading.Tasks;
using StackExchange.Redis;
public class HardwareManagerDistributed
{
private readonly ConnectionMultiplexer redis;
private readonly string instanceId = Guid.NewGuid().ToString();
public HardwareManagerDistributed(string redisConnectionString)
{
redis = ConnectionMultiplexer.Connect(redisConnectionString);
}
public async Task AccessHardwareAsync(string comPort, string operation)
{
var db = redis.GetDatabase();
var lockKey = $"lock:{comPort}";
var lockValue = Guid.NewGuid().ToString();
var stopwatch = Stopwatch.StartNew();
bool acquired = false;
Logger.Log($"[Distributed][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 尝试获取 {comPort} 分布式锁 ({operation})");
// 重试获取锁(最多5秒)
for (int i = 0; i < 50; i++)
{
if (await db.StringSetAsync(lockKey, lockValue, TimeSpan.FromSeconds(10), When.NotExists))
{
acquired = true;
break;
}
await Task.Delay(100);
}
if (!acquired)
{
throw new TimeoutException($"[Distributed][Instance {instanceId}] 无法获取 {comPort} 分布式锁");
}
try
{
PerformanceTracker.RecordWaitTime(stopwatch.ElapsedMilliseconds);
Logger.Log($"[Distributed][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 获取 {comPort} 分布式锁,执行 {operation}...");
await Task.Delay(operation == "read" ? 500 : 1000);
Logger.Log($"[Distributed][Instance {instanceId}] Thread {Thread.CurrentThread.ManagedThreadId} 完成 {comPort} 的 {operation}");
}
finally
{
// 仅释放自己的锁
if (await db.StringGetAsync(lockKey) == lockValue)
{
await db.KeyDeleteAsync(lockKey);
}
}
}
}
说明:
-
分布式锁:使用 Redis SET NX 实现锁,10秒过期防止死锁。
-
重试机制:5秒内重试获取锁。
-
锁安全性:通过 lockValue 确保只释放自己的锁。
-
适用场景:跨进程/机器的资源同步。
6. 多线程、多实例测试
以下是测试代码,模拟多线程、多实例并发访问。
csharp
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// 创建多个实例
var syncManager1 = new HardwareManagerSync();
var syncManager2 = new HardwareManagerSync();
var asyncManager = new HardwareManagerAsync();
var rwManager = new HardwareManagerReadWrite();
var distributedManager = new HardwareManagerDistributed("localhost:6379");
// 任务列表
var tasks = new Task[]
{
// 同步锁测试
Task.Run(() => syncManager1.AccessHardware("COM1", "write")),
Task.Run(() => syncManager1.AccessHardware("COM2", "read")),
Task.Run(() => syncManager2.AccessHardware("COM1", "write")),
Task.Run(() => syncManager2.AccessTwoPorts("COM1", "COM2", "read")),
// 异步锁测试
asyncManager.AccessHardwareAsync("COM1", "write"),
asyncManager.AccessHardwareAsync("COM1", "read"),
asyncManager.AccessHardwareAsync("COM2", "write"),
asyncManager.AccessTwoPortsAsync("COM2", "COM3", "read"),
// 读写锁测试
rwManager.ReadHardwareAsync("COM1"),
rwManager.ReadHardwareAsync("COM1"), // 并行读
rwManager.WriteHardwareAsync("COM1"),
rwManager.ReadHardwareAsync("COM2"),
rwManager.WriteHardwareAsync("COM2"),
// 分布式锁测试
distributedManager.AccessHardwareAsync("COM1", "write"),
distributedManager.AccessHardwareAsync("COM1", "read"),
distributedManager.AccessHardwareAsync("COM2", "write")
};
// 等待所有任务完成
try
{
await Task.WhenAll(tasks);
Logger.Log("所有任务完成");
PerformanceTracker.PrintStats();
}
catch (Exception ex)
{
Logger.Log($"发生错误: {ex.Message}");
}
// 清理资源
asyncManager.Cleanup();
}
}
说明:
-
多线程:通过 Task.Run 和异步方法模拟并发。
-
多实例:syncManager1 和 syncManager2 使用实例级锁,asyncManager 和 rwManager 使用静态锁。
-
读写操作:区分读(500ms)和写(1000ms)操作。
-
错误处理:捕获超时等异常,记录日志。
-
性能监控:统计锁等待时间,分析并发性能。
7. 死锁预防机制
-
统一锁顺序:AccessTwoPorts 和 AccessTwoPortsAsync 按端口名称排序获取锁。
-
超时机制:异步锁和读写锁设置5秒超时,分布式锁重试5秒。
-
避免嵌套:尽量分解多端口操作,减少锁嵌套。
-
锁过期:分布式锁设置10秒过期时间,防止死锁。
-
资源清理:异步锁提供 Cleanup 方法释放 SemaphoreSlim。
8. 运行结果示例
运行代码,输出类似(具体线程 ID 和顺序因调度而异):
[18:35:00.123] [Sync][Instance 1234] Thread 5 尝试获取 COM1 锁 (write)
[18:35:00.124] [Sync][Instance 1234] Thread 5 获取 COM1 锁,执行 write...
[18:35:00.125] [Async][Instance 5678] Thread 6 尝试获取 COM2 锁 (write)
[18:35:00.126] [Async][Instance 5678] Thread 6 获取 COM2 锁,执行 write...
[18:35:00.127] [ReadWrite][Instance 9012] Thread 7 尝试获取 COM1 读锁
[18:35:00.128] [ReadWrite][Instance 9012] Thread 8 尝试获取 COM1 读锁
[18:35:00.129] [ReadWrite][Instance 9012] Thread 7 获取 COM1 读锁,执行读取...
[18:35:00.130] [ReadWrite][Instance 9012] Thread 8 获取 COM1 读锁,执行读取...
[18:35:00.630] [ReadWrite][Instance 9012] Thread 7 完成 COM1 的读取
[18:35:00.631] [ReadWrite][Instance 9012] Thread 8 完成 COM1 的读取
[18:35:01.124] [Sync][Instance 1234] Thread 5 完成 COM1 的 write
[18:35:01.126] [Async][Instance 5678] Thread 6 完成 COM2 的 write
[18:35:01.127] [Distributed][Instance 3456] Thread 9 尝试获取 COM1 分布式锁 (write)
[18:35:01.128] [Distributed][Instance 3456] Thread 9 获取 COM1 分布式锁,执行 write...
[18:35:02.129] [Distributed][Instance 3456] Thread 9 完成 COM1 的 write
[18:35:02.130] 所有任务完成
[18:35:02.131] 性能统计: 总锁等待时间 = 150ms, 平均等待时间 = 10ms, 锁尝试次数 = 15
分析:
-
并发性:不同端口操作并行,同一端口操作序列化。
-
读写锁:COM1 的多个读操作并行执行。
-
实例隔离:syncManager1 和 syncManager2 的 COM1 操作互不干扰。
-
分布式锁:确保跨实例的线程安全。
9. 性能优化与注意事项
-
同步锁:
-
优点:实现简单,适合低并发。
-
缺点:线程阻塞,性能较低。
-
优化:使用 ConcurrentDictionary 避免锁字典竞争。
-
-
异步锁:
-
优点:非阻塞,适合高并发异步场景。
-
优化:预分配锁、超时机制、资源清理。
-
注意:确保 finally 释放锁。
-
-
读写锁:
-
优点:读多写少场景高效。
-
优化:结合异步操作,减少写锁等待。
-
注意:避免读锁升级为写锁。
-
-
分布式锁:
-
优点:支持跨进程/机器。
-
优化:锁过期、重试机制、Redis 高可用。
-
注意:确保 Redis 连接稳定。
-
-
性能监控:通过 PerformanceTracker 分析锁等待时间,优化瓶颈。
-
错误处理:捕获超时和异常,确保系统鲁棒性。
10. 总结
-
同步锁:适合简单同步场景,实例级隔离。
-
异步锁:支持高并发,静态锁共享资源。
-
读写锁:优化读多写少场景。
-
分布式锁:支持跨进程同步,适合分布式系统。
-
死锁预防:锁顺序、超时、避免嵌套、锁过期。
-
扩展性:代码支持复杂业务逻辑(读/写操作、性能监控、日志)。
如果需要进一步优化(如特定硬件逻辑、更高并发测试、Redis 集群支持),请提供更多细节,我可以继续完善代码!
更多推荐
所有评论(0)