前言
在多线程编程中,线程之间的资源共享和并发访问可能导致数据竞争、死锁等严重问题。因此,线程同步机制是保障程序正确性和稳定性的重要手段。
C# 提供了多种同步机制,包括 lock、Interlocked、Monitor、SpinLock、WaitHandle、Mutex、Semaphore、Events、Barrier 和 ReaderWriterLockSlim 等。它们虽然都用于线程同步,但在底层实现、适用场景和性能特点上各有不同。
本文将从底层原理、使用方式、性能对比等方面对这些机制进行系统性分析,帮助开发根据实际需求选择最合适的同步策略。
正文
1、lock 关键字
底层操作
- lock 是基于 Monitor 实现的语法糖。
- 编译器会自动生成 try-finally 块,确保锁的释放。
特点
- 基于内核对象(SyncBlock)。
- 使用简单,适合保护简单的共享资源。
- 可能引入死锁问题。
示例代码
private staticreadonlyobject _lock = newobject();
privatestaticint _counter = 0;
public static void IncrementCounter()
{
lock (_lock)
{
_counter++;
}
}
2、Interlocked 类
底层操作
- 利用 CPU 的原子指令(如 LOCK CMPXCHG)实现。
- 不涉及锁,直接操作内存。
特点
- 轻量级,性能高。
- 仅支持简单类型(如 int, long)的原子操作。
示例代码
private static int _counter
= 0;
public static void IncrementCounter()
{
Interlocked.Increment(ref _counter);
}
3、Monitor 类
底层操作
- 基于 CLR 内部结构 SyncBlock。
- 支持 Enter/Exit、Wait/Pulse 等复杂控制。
特点
- 比 lock 更灵活,适用于复杂逻辑。
- 性能较低,涉及内核切换。
示例代码
private staticreadonlyobject _lock
= newobject();
public static void DoWork()
{
Monitor.Enter(_lock);
try
{
// 临界区代码
}
finally
{
Monitor.Exit(_lock);
}
}
4、SpinLock 结构
底层操作
- 使用自旋机制,在获取锁失败时不断尝试。
- 基于 CPU 原子操作实现。
特点
- 避免上下文切换开销,适合短时间等待。
- 长时间等待浪费 CPU 资源。
示例代码
private static SpinLock
_spinLock = new SpinLock();
public static void DoWork()
{
bool lockTaken = false;
try
{
_spinLock.Enter(ref lockTaken);
// 临界区代码
}
finally
{
if (lockTaken)
_spinLock.Exit();
}
}
5、WaitHandle 类
底层操作
- 基于内核对象(事件、信号量、互斥体)。
- 支持跨进程同步。
特点
- 适用于复杂的线程通信。
- 性能较低,因为涉及内核切换。
示例代码
private static EventWaitHandle
_waitHandle = new AutoResetEvent(false);
public static void DoWork()
{
_waitHandle.WaitOne(); // 等待信号
// 继续执行
}
public static void Signal()
{
_waitHandle.Set(); // 发送信号
}
6、Mutex 类
底层操作
- 基于内核对象的互斥体。
- 支持递归锁和跨进程同步。
特点
- 重量级,性能较低。
- 适用于跨进程资源访问控制。
示例代码
private static Mutex _mutex
= new Mutex();
public static void DoWork()
{
_mutex.WaitOne();
try
{
// 临界区代码
}
finally
{
_mutex.ReleaseMutex();
}
}
7、Semaphore 类
底层操作
- 基于内核对象的信号量。
- 控制多个线程同时访问资源。
特点
- 支持资源池管理。
- 允许多个线程同时访问,但数量有限。
示例代码
private static Semaphore
_semaphore = new Semaphore(3, 3); // 最多允许3个线程访问
public static void DoWork()
{
_semaphore.WaitOne();
try
{
// 临界区代码
}
finally
{
_semaphore.Release();
}
}
8、Events 类
底层操作
- 基于事件对象,支持手动或自动重置。
特点
- 灵活的线程间通信方式。
- 性能低,适合通知类任务。
示例代码
private static ManualResetEventSlim
_event = new ManualResetEventSlim(false);
public static void DoWork()
{
_event.Wait(); // 等待信号
// 继续执行
}
public static void Signal()
{
_event.Set(); // 发送信号
}
9、Barrier 类
底层操作
- 自旋 + 内核事件结合实现。
- 多线程分阶段同步。
特点
- 适用于并行计算中的阶段性同步。
- 性能较高,适合多线程协同。
示例代码
private static Barrier
_barrier = new Barrier(3); // 等待3个线程
public static void DoWork()
{
// 执行部分工作
_barrier.SignalAndWait(); // 等待其他线程
// 继续执行
}
10、ReaderWriterLockSlim 类
底层操作
- 自旋 + 内核事件结合实现。
- 支持读写分离,提升并发性能。
特点
- 读操作可并发执行。
- 写操作独占资源。
示例代码
private static ReaderWriterLockSlim
_rwLock = new ReaderWriterLockSlim();
public static void Read()
{
_rwLock.EnterReadLock();
try
{
// 读取操作
}
finally
{
_rwLock.ExitReadLock();
}
}
public static void Write()
{
_rwLock.EnterWriteLock();
try
{
// 写入操作
}
finally
{
_rwLock.ExitWriteLock();
}
}
总结对比表
|
同步机制 |
底层实现 |
性能 |
适用场景 |
跨进程支持 |
递归锁支持 |
|
lock |
Monitor |
中等 |
简单临界区保护 |
❌ |
✅ |
|
Interlocked |
CPU 原子指令 |
高 |
简单数值操作 |
❌ |
❌ |
|
Monitor |
SyncBlock |
中等 |
复杂同步逻辑 |
❌ |
✅ |
|
SpinLock |
自旋等待 |
高 |
短时间临界区 |
❌ |
❌ |
|
WaitHandle |
内核事件 |
低 |
信号通知 |
✅ |
❌ |
|
Mutex |
内核互斥体 |
低 |
跨进程同步 |
✅ |
✅ |
|
Semaphore |
内核信号量 |
低 |
资源限制访问 |
✅ |
❌ |
|
Events |
内核事件 |
低 |
信号通知 |
✅ |
❌ |
|
Barrier |
自旋+事件 |
高 |
多线程同步点 |
❌ |
❌ |
|
ReaderWriterLockSlim |
自旋+事件 |
高 |
读写分离场景 |
❌ |
✅ |
选择建议
- 高性能场景:优先选择 Interlocked、SpinLock 或 ReaderWriterLockSlim。
- 简单同步:使用 lock 或 Monitor。
- 复杂同步:使用 WaitHandle、Events 或 Barrier。
- 跨进程同步:使用 Mutex 或 Semaphore。
总结
每种同步机制都有其独特的优势和局限性。在实际开发中,应根据具体场景选择最合适的机制:
- 如果你追求极致性能,且只处理简单变量操作,可以考虑 Interlocked;
- 如果需要更细粒度的控制,可以使用 Monitor;
- 如果你需要避免线程频繁切换,可以使用 SpinLock;
- 如果你要实现读写分离,提高并发性能,可以选择 ReaderWriterLockSlim;
- 如果你面对的是跨进程资源竞争,那么 Mutex 和 Semaphore 是理想选择。
掌握这些机制的底层原理和使用方法,有助于编写出更加高效、稳定、安全的多线程程序。
![]() |
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |




浙公网安备 33010602011771号