多线程-信号量
定义
在C#中,存在多种类型的信号量或同步机制来控制对共享资源的访问。这些信号量通常用于多线程编程,以确保资源在并发访问时的正确性和一致性。以下是一些主要的信号量及其描述:
- AutoResetEvent:
- 当线程调用
WaitOne
方法时,它会阻塞,直到另一个线程调用Set
方法。 - 一旦
Set
方法被调用,等待的线程中的一个(如果有的话)将被释放,并且AutoResetEvent
会自动重置为未发信号状态,等待下一次的Set
调用。
- 当线程调用
- ManualResetEvent:
- 与
AutoResetEvent
类似,但ManualResetEvent
在Set
方法被调用后不会自动重置。 - 它需要手动调用
Reset
方法才能回到未发信号状态。
- 与
- CountdownEvent:
- 这是一个反向计数的信号量。
- 在创建对象时设置一个初始值,每当线程调用
Signal
方法时,计数器就会减一。 - 当计数器归零时,所有等待的线程都会被释放。
- EventWaitHandle:
- 这是一个更通用的等待句柄,可以配置为自动重置或手动重置。
- 它实际上结合了
AutoResetEvent
和ManualResetEvent
的功能。
- Semaphore 和 SemaphoreSlim:
- 信号量是一种计数的互斥锁定。
- 它们定义了允许同时访问受保护的资源的线程数。
Semaphore
类可以命名,允许在不同进程之间同步。SemaphoreSlim
是Semaphore
的轻量级版本,对较短等待时间进行了优化
ManualResetEvent的用法
- 初始化:
- 创建一个ManualResetEvent实例,并设置其初始状态。通常,初始状态可以设置为false(表示事件尚未发生)或true(表示事件已经发生)。例如:
ManualResetEvent mre = new ManualResetEvent(false);
- 创建一个ManualResetEvent实例,并设置其初始状态。通常,初始状态可以设置为false(表示事件尚未发生)或true(表示事件已经发生)。例如:
- 等待事件:
- 在需要等待事件发生的线程中,调用
WaitOne()
方法。如果ManualResetEvent的状态为false,该方法会阻塞当前线程,直到状态变为true。例如:mre.WaitOne();
- 在需要等待事件发生的线程中,调用
- 发出事件:
- 当某个条件满足或某个事件发生时,通过调用
Set()
方法来通知等待的线程。这会将ManualResetEvent的状态设置为true,从而允许在WaitOne()
处阻塞的线程继续执行。例如:mre.Set();
- 当某个条件满足或某个事件发生时,通过调用
- 重置事件:
- 如果需要重置ManualResetEvent的状态为false,可以调用
Reset()
方法。之后,线程在调用WaitOne()
时会再次阻塞。例如:mre.Reset();
- 如果需要重置ManualResetEvent的状态为false,可以调用
- 多线程通知:
- 一个重要的特性是,一次
Set()
调用可以释放所有在WaitOne()
上阻塞的线程,这使得ManualResetEvent非常适合用于广播式通知场景。
- 一个重要的特性是,一次
AutoResetEvent的用法
- 初始化:
- 创建一个AutoResetEvent实例,并设置其初始状态,通常设置为false。例如:
AutoResetEvent autoEvent = new AutoResetEvent(false);
- 创建一个AutoResetEvent实例,并设置其初始状态,通常设置为false。例如:
- 等待事件:
- 在需要等待事件发生的线程中,调用
WaitOne()
方法。如果AutoResetEvent的状态为false,线程会在此处阻塞。例如:autoEvent.WaitOne();
- 在需要等待事件发生的线程中,调用
- 发出事件:
- 当需要通知等待的线程时,调用
Set()
方法。这会将AutoResetEvent的状态设置为true,并唤醒一个等待的线程(如果有的话)。状态随后会自动重置为false。例如:autoEvent.Set();
- 当需要通知等待的线程时,调用
- 单线程通知:
- 与ManualResetEvent不同,AutoResetEvent在唤醒一个线程后会自动将状态重置为false。这意味着每次
Set()
调用只会唤醒一个线程,使其适合用于一对一的通知场景。
- 与ManualResetEvent不同,AutoResetEvent在唤醒一个线程后会自动将状态重置为false。这意味着每次
Semaphore的用法
Semaphore
是一种同步原语,用于控制对共享资源的访问。它允许多个线程同时访问资源,但限制同时访问的最大线程数。这非常适合于控制对有限资源的并发访问,例如数据库连接池或文件句柄。
Semaphore
类位于 System.Threading
命名空间中,其构造函数通常接受两个参数:初始可用资源和最大可用资源。这两个值可以是相同的,也可以不同,具体取决于你的使用场景。
CountdownEvent的用法
CountdownEvent 实例化是需要传入一个int 类型作为InitialCount初始值,CountdownEvent信号量的释放很特别,只有当Countdown类的实例的CurrentCount等于0时才会释放我们的信号量,Signal()方法每次调用都会使得CurrentCount进行-1操作。Reset()方法会重置为实例化对象时传递的参数值,也可以Reset(100)对我们的InitialCount重新赋值。
代码
demo
public class XHLDemo { //一次set释放一个等待的线程 public AutoResetEvent autoResetEvent = new AutoResetEvent(false); //一次set释放所有等待的线程 public ManualResetEvent manualResetEvent = new ManualResetEvent(false); //每次调用Signal会减去对应的值,当Count=0时,释放信号量,也会释放所有等待的线程 public CountdownEvent countdownEvent=new CountdownEvent(3); //参数:初始化空闲线程数,允许同时最大线程数 public Semaphore Semaphore=new Semaphore(1, 1); public void TestSemaphore() { Task.Run(() => { SemaphoreEvent(); }); Task.Run(() => { SemaphoreEvent(); }); Task.Run(() => { SemaphoreEvent(); }); Task.Run(() => { SemaphoreEvent(); }); Task.Run(() => { SemaphoreEvent(); }); Task.Run(() => { SemaphoreEvent(); }); Thread.Sleep(5000); } public void SemaphoreEvent() { Semaphore.WaitOne(); Thread.Sleep(1000); Console.WriteLine("触发 SemaphoreEvent"); Semaphore.Release(); } public void TestCountdownEvent() { Task.Run(() => { CountdownEvent(); }); Task.Run(() => { CountdownEvent(); }); Thread.Sleep(1000); Console.WriteLine("释放 CountdownEvent 信号量"); countdownEvent.Signal(3); } public void CountdownEvent() { countdownEvent.Wait(); Console.WriteLine("触发 CountdownEvent"); countdownEvent.Reset(); } public void TestManualResetEvent() { Task.Run(() => { ManualResetEvent(); }); Task.Run(() => { ManualResetEvent(); }); Thread.Sleep(1000); Console.WriteLine("释放 ManualResetEvent 信号量"); manualResetEvent.Set(); } public void ManualResetEvent() { manualResetEvent.WaitOne();//等待 Console.WriteLine("触发 ManualResetEvent"); manualResetEvent.Reset();//重置信号量 } public void TestAutoResetEvent() { Task.Run(() => { AutoResetEvent(); }); Task.Run(() => { AutoResetEvent(); }); Thread.Sleep(1000); Console.WriteLine("释放 AutoResetEvent 信号量"); autoResetEvent.Set(); } public void AutoResetEvent() { autoResetEvent.WaitOne(); Console.WriteLine("触发 AutoResetEvent"); autoResetEvent.Reset(); } }
调用
XHLDemo xHL =new XHLDemo(); xHL.TestSemaphore(); xHL.TestManualResetEvent(); xHL.TestAutoResetEvent(); xHL.TestCountdownEvent();
喜欢 C#、SQL、Web