原子锁通过 `Interlocked.CompareExchange` 实现“无锁”竞争。这种方式适用于简单的原子操作。

private static int isLock;private static int ceInt;
private static void CEIntAdd(){    for (var i = 0; i < runTimes; i++)    {        while (Interlocked.CompareExchange(ref isLock, 1, 0) == 1)        {            Thread.Sleep(1);        }        ceInt++;        Interlocked.Exchange(ref isLock, 0);    }}
View Code

临界区通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。C# 中的 `lock` 语法是临界区(Monitor)的一个语法糖。

private static object obj = new object();private static int lockInt;
private static void LockIntAdd(){    for (var i = 0; i < runTimes; i++)    {        lock (obj)        {            lockInt++;        }    }}
View Code

原子性操作是一种特例,它天生线程安全,无需加锁。

private static int atomicInt;
private static void AtomicIntAdd(){    for (var i = 0; i < runTimes; i++)    {        Interlocked.Increment(ref atomicInt);    }}
View Code

读写锁允许在有其他程序正在写的情况下读取资源,适合读多写少的场景

private static ReaderWriterLockSlim LockSlim = new ReaderWriterLockSlim();private static int lockSlimInt;
private static void LockSlimIntAdd(){    for (var i = 0; i < runTimes; i++)    {        LockSlim.EnterWriteLock();        lockSlimInt++;        LockSlim.ExitWriteLock();    }}
View Code

信号量用于控制对有限资源的并发访问

private static Semaphore sema = new Semaphore(1, 1);private static int semaphoreInt;
private static void SemaphoreIntAdd(){    for (var i = 0; i < runTimes; i++)    {        sema.WaitOne();        semaphoreInt++;        sema.Release();    }}
View Code

事件用于通知线程某些事件已经发生,从而启动后续任务

public static AutoResetEvent autoResetEvent = new AutoResetEvent(true);private static int autoResetEventInt;
private static void AutoResetEventIntAdd(){    for (var i = 0; i < runTimes; i++)    {        if (autoResetEvent.WaitOne())        {            autoResetEventInt++;            autoResetEvent.Set();        }    }}
View Code

互斥量(Mutex)不仅可以处理线程间的资源竞争,还可以处理进程间的资源竞争。

private static Mutex mutex = new Mutex();private static int mutexInt;
private static void MutexIntAdd(){    for (var i = 0; i < runTimes; i++)    {        mutex.WaitOne();        mutexInt++;        mutex.ReleaseMutex();    }}
View Code

性能测试代码

private static int noLockInt;
private static void NoLockIntAdd(){    for (var i = 0; i < runTimes; i++)    {        noLockInt++;    }}
View Code
private static int runTimes = 10000000; // 可以自己设置private static int loopTimes = 10; // 可以自己设置
private static void Run(){    var stopwatch = new Stopwatch();    var taskList = new Task[loopTimes]; // 设置线程数
    Console.WriteLine();    Console.WriteLine($"              线程数:{loopTimes}");    Console.WriteLine($"            执行次数:{runTimes}");    Console.WriteLine($"        校验值应等于:{runTimes * loopTimes}");
    // AtomicIntAdd    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { AtomicIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"AtomicIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{atomicInt}");
    // CEIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { CEIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"CEIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{ceInt}");
    // LockIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { LockIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"LockIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{lockInt}");
    // MutexIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { MutexIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"MutexIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{mutexInt}");
    // LockSlimIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { LockSlimIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"LockSlimIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{lockSlimInt}");
    // SemaphoreIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { SemaphoreIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"SemaphoreIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{semaphoreInt}");
    // AutoResetEventIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { AutoResetEventIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"AutoResetEventIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{autoResetEventInt}");
    // NoLockIntAdd    taskList = new Task[loopTimes];    stopwatch.Restart();    for (var i = 0; i < loopTimes; i++)    {        taskList[i] = Task.Factory.StartNew(() => { NoLockIntAdd(); });    }    Task.WaitAll(taskList);    Console.WriteLine($"NoLockIntAdd, 总耗时:{stopwatch.ElapsedMilliseconds}毫秒, 校验值:{noLockInt}");    Console.WriteLine();}
private static string GetFormat(string start){    return start + "开始执行";}
View Code

在多线程并发测试中,不同锁的性能表现如下:
1. 无锁:不加锁的代码运行最快,但不适合资源竞争场景。
2. 原子锁:`Interlocked.CompareExchange` 表现出优越的性能,适合简单的原子操作。
3. 临界区:`lock` 关键字实现的临界区表现出良好的性能,适合控制数据访问。
4. 原子性操作:`Interlocked.Increment` 等原子性操作适合变量的自增自减,但适用性有限。
5. 读写锁:`ReaderWriterLockSlim` 支持多线程读取,适合读多写少的场景。
6. 信号量、事件、互斥量:这些锁在处理资源竞争时性能较差,但它们在特定场景下有其适用性。

posted @ 2025-05-18 11:49  彪悍的代码不需要注释  阅读(13)  评论(0)    收藏  举报
39
0