更详细的 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 集群支持),请提供更多细节,我可以继续完善代码!

更多推荐