多线程-信号量

 定义

在C#中,存在多种类型的信号量或同步机制来控制对共享资源的访问。这些信号量通常用于多线程编程,以确保资源在并发访问时的正确性和一致性。以下是一些主要的信号量及其描述:

  1. AutoResetEvent:
    • 当线程调用WaitOne方法时,它会阻塞,直到另一个线程调用Set方法。
    • 一旦Set方法被调用,等待的线程中的一个(如果有的话)将被释放,并且AutoResetEvent会自动重置为未发信号状态,等待下一次的Set调用。
  2. ManualResetEvent:
    • AutoResetEvent类似,但ManualResetEventSet方法被调用后不会自动重置。
    • 它需要手动调用Reset方法才能回到未发信号状态。
  3. CountdownEvent:
    • 这是一个反向计数的信号量。
    • 在创建对象时设置一个初始值,每当线程调用Signal方法时,计数器就会减一。
    • 当计数器归零时,所有等待的线程都会被释放。
  4. EventWaitHandle:
    • 这是一个更通用的等待句柄,可以配置为自动重置或手动重置。
    • 它实际上结合了AutoResetEventManualResetEvent的功能。
  5. Semaphore 和 SemaphoreSlim:
    • 信号量是一种计数的互斥锁定。
    • 它们定义了允许同时访问受保护的资源的线程数。
    • Semaphore类可以命名,允许在不同进程之间同步。
    • SemaphoreSlimSemaphore的轻量级版本,对较短等待时间进行了优化

ManualResetEvent的用法

  1. 初始化:
    • 创建一个ManualResetEvent实例,并设置其初始状态。通常,初始状态可以设置为false(表示事件尚未发生)或true(表示事件已经发生)。例如:ManualResetEvent mre = new ManualResetEvent(false);
  2. 等待事件:
    • 在需要等待事件发生的线程中,调用WaitOne()方法。如果ManualResetEvent的状态为false,该方法会阻塞当前线程,直到状态变为true。例如:mre.WaitOne();
  3. 发出事件:
    • 当某个条件满足或某个事件发生时,通过调用Set()方法来通知等待的线程。这会将ManualResetEvent的状态设置为true,从而允许在WaitOne()处阻塞的线程继续执行。例如:mre.Set();
  4. 重置事件:
    • 如果需要重置ManualResetEvent的状态为false,可以调用Reset()方法。之后,线程在调用WaitOne()时会再次阻塞。例如:mre.Reset();
  5. 多线程通知:
    • 一个重要的特性是,一次Set()调用可以释放所有在WaitOne()上阻塞的线程,这使得ManualResetEvent非常适合用于广播式通知场景。

AutoResetEvent的用法

  1. 初始化:
    • 创建一个AutoResetEvent实例,并设置其初始状态,通常设置为false。例如:AutoResetEvent autoEvent = new AutoResetEvent(false);
  2. 等待事件:
    • 在需要等待事件发生的线程中,调用WaitOne()方法。如果AutoResetEvent的状态为false,线程会在此处阻塞。例如:autoEvent.WaitOne();
  3. 发出事件:
    • 当需要通知等待的线程时,调用Set()方法。这会将AutoResetEvent的状态设置为true,并唤醒一个等待的线程(如果有的话)。状态随后会自动重置为false。例如:autoEvent.Set();
  4. 单线程通知:
    • 与ManualResetEvent不同,AutoResetEvent在唤醒一个线程后会自动将状态重置为false。这意味着每次Set()调用只会唤醒一个线程,使其适合用于一对一的通知场景。 

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();

 

 

 

posted @ 2024-06-16 23:24  DaiWK  阅读(9)  评论(0编辑  收藏  举报