概述
Mutex 和 Semaphore 是内核同步对象,支持跨进程同步。相比 lock/Monitor(用户态),它们有更大的开销但功能更强。
Mutex(互斥体)
Mutex 确保同一时刻只有一个线程(或进程)拥有资源。
进程内使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| using System.Threading;
Mutex mutex = new Mutex();
try { if (mutex.WaitOne(TimeSpan.FromSeconds(1))) { Console.WriteLine("获得锁,执行操作"); } else { Console.WriteLine("获取锁超时"); } } finally { mutex.ReleaseMutex(); }
|
跨进程互斥
通过命名 Mutex 实现进程间同步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Mutex mutex = new Mutex(false, "Global\\MyApp_SingleInstance");
bool isFirstInstance; Mutex mutex = new Mutex(true, "Global\\MyApp_SingleInstance", out isFirstInstance);
if (!isFirstInstance) { Console.WriteLine("已有实例运行中,程序退出"); return; }
Run();
|
单实例应用完整示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| using System; using System.Threading; using System.Windows.Forms;
class Program { [STAThread] static void Main() { using (Mutex mutex = new Mutex(true, "Global\\MyWinApp_SingleInstance", out bool isFirst)) { if (!isFirst) { MessageBox.Show("程序已在运行"); return; } Application.Run(new MainForm()); } } }
|
跨进程锁
1 2 3 4 5 6 7
| Mutex mutex = new Mutex(false, "Global\\SharedResource"); mutex.WaitOne();
mutex.ReleaseMutex();
|
Semaphore(信号量)
Semaphore 限制同时访问资源的线程数。
本地信号量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Semaphore semaphore = new Semaphore(2, 3);
for (int i = 0; i < 10; i++) { int taskId = i; Task.Run(() => { semaphore.WaitOne(); try { Console.WriteLine($"{taskId} 获得信号量,线程: {Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } finally { semaphore.Release(); Console.WriteLine($"{taskId} 释放信号量"); } }); }
|
使用 using 简化
1 2 3 4 5 6 7 8 9 10 11
| using SemaphoreSlim semaphore = new SemaphoreSlim(2, 3);
await semaphore.WaitAsync(); try { } finally { semaphore.Release(); }
|
命名信号量(跨进程)
1 2 3 4
| Semaphore semaphore = new Semaphore(2, 3, "Global\\MyNamedSemaphore");
|
SemaphoreSlim(推荐)
SemaphoreSlim 是轻量级版本,不支持跨进程,性能更好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| using System.Threading;
SemaphoreSlim semaphore = new SemaphoreSlim(2, 3);
semaphore.Wait(); try { } finally { semaphore.Release(); }
await semaphore.WaitAsync(); try { await DoWorkAsync(); } finally { semaphore.Release(); }
if (await semaphore.WaitAsync(TimeSpan.FromSeconds(1))) { try { } finally { semaphore.Release(); } }
|
实际应用场景
连接池限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class DatabaseConnectionPool { private readonly SemaphoreSlim _semaphore; private readonly List<DbConnection> _connections; public DatabaseConnectionPool(int maxConnections) { _semaphore = new SemaphoreSlim(maxConnections, maxConnections); _connections = new List<DbConnection>(); for (int i = 0; i < maxConnections; i++) { _connections.Add(CreateConnection()); } } public async Task<DbConnection> GetConnectionAsync() { await _semaphore.WaitAsync(); lock (_connections) { var conn = _connections.First(c => c.State == ConnectionState.Closed); conn.Open(); return conn; } } public void ReturnConnection(DbConnection connection) { connection.Close(); _semaphore.Release(); } }
|
API 限流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class RateLimiter { private readonly SemaphoreSlim _semaphore; private readonly int _maxRequests; public RateLimiter(int maxConcurrentRequests) { _maxRequests = maxConcurrentRequests; _semaphore = new SemaphoreSlim(maxConcurrentRequests, maxConcurrentRequests); } public async Task<T> ExecuteAsync<T>(Func<Task<T>> action) { await _semaphore.WaitAsync(); try { return await action(); } finally { _semaphore.Release(); } } }
|
对比
| 特性 |
Mutex |
Semaphore |
SemaphoreSlim |
| 跨进程 |
支持 |
支持 |
不支持 |
| 性能 |
慢 |
慢 |
快 |
| 异步等待 |
不支持 |
不支持 |
支持 (WaitAsync) |
| 超时控制 |
WaitOne(TimeSpan) |
WaitOne(TimeSpan) |
Wait/WaitAsync |
| 推荐场景 |
单例/跨进程锁 |
跨进程并发控制 |
进程内并发控制 |
注意事项
- 始终释放资源:使用 try/finally 或 using
- 命名格式:Global\ 表示全局(跨会话),Local\ 表示仅当前会话
- 权限问题:跨进程可能需要调整 ACL
- 避免持有锁执行耗时操作
- SemaphoreSlim 比 Semaphore 更适合 .NET 应用
1 2 3 4 5 6 7 8 9 10 11 12 13
| SemaphoreSlim sem = null; try { sem = new SemaphoreSlim(1, 1); await sem.WaitAsync(); } finally { sem?.Release(); sem?.Dispose(); }
|
参考资源