您的位置:

C#线程等待

一、基础概念

在多任务环境下,线程等待是非常重要的一个概念。线程等待可以让一个线程等待另外一个线程完成某些操作,然后再继续执行。在C#中,线程等待是通过System.Threading命名空间中的WaitHandle类和其派生类来实现的。

WaitHandle类提供WaitOne()和WaitAny()方法,它们都可以让一个线程等待某个事件,直到该事件发生或超时。WaitOne()方法会等待一个WaitHandle对象的信号,并且支持超时;WaitAny()方法会等待多个WaitHandle对象中的任意一个被信号激活,并且支持超时。

在具体的应用场景中,我们可以使用ManualResetEvent、AutoResetEvent、CountdownEvent和SemaphoreSlim等类来创建WaitHandle对象。

二、ManualResetEvent和AutoResetEvent

ManualResetEvent和AutoResetEvent都是WaitHandle的派生类,它们可以用于线程等待。在 ManualResetEvent 中,线程会一直等待直到该事件被信号激活。而在 AutoResetEvent 中,线程会等待事件被信号激活一次,然后自动重置,以便于下次被信号激活。

下面是使用ManualResetEvent实现线程等待的代码示例:

ManualResetEvent event1 = new ManualResetEvent(false);

ThreadPool.QueueUserWorkItem(state =>
{
    Console.WriteLine("Thread 1 is running");
    Thread.Sleep(1000);
    Console.WriteLine("Thread 1 set the event");
    event1.Set();
});

Console.WriteLine("Main thread is waiting for event");
event1.WaitOne();
Console.WriteLine("Main thread received event");

上述示例使用ManualResetEvent实现了一个线程等待的功能。在主线程中,首先创建了一个ManualResetEvent对象,并且初始化为未激活状态。然后开启一个新的线程,在该线程中等待1秒钟,并且在1秒钟后激活ManualResetEvent对象。在主线程中调用event1.WaitOne()方法等待事件的激活,直到该事件被激活后,主线程才会继续执行。

三、CountdownEvent和SemaphoreSlim

CountdownEvent和SemaphoreSlim也是WaitHandle的派生类。CountdownEvent可以用来等待一组操作完成,而SemaphoreSlim可以用来控制同时执行的线程数量。

下面是使用CountdownEvent实现线程等待的代码示例:

CountdownEvent countdown = new CountdownEvent(3);

for (int i = 1; i <= 3; i++)
{
    ThreadPool.QueueUserWorkItem(state =>
    {
        Console.WriteLine($"Thread {i} is running");
        Thread.Sleep(1000);
        Console.WriteLine($"Thread {i} is done");
        countdown.Signal();
    });
}

countdown.Wait();
Console.WriteLine("All threads are done");

上述示例使用CountdownEvent实现了同时等待多个线程完成的功能。首先创建了一个CountdownEvent对象,并且把初始计数器设置为3。然后开启三个新的线程,在每个线程中等待1秒钟,并且在1秒钟后为CountdownEvent对象计数。在主线程中调用countdown.Wait()方法等待所有的线程完成,并且在所有线程完成后继续执行。

下面是使用SemaphoreSlim实现控制线程数量的代码示例:

SemaphoreSlim semaphore = new SemaphoreSlim(3);

for (int i = 1; i <= 5; i++)
{
    ThreadPool.QueueUserWorkItem(async state =>
    {
        await semaphore.WaitAsync();
        Console.WriteLine($"Thread {i} start");
        Thread.Sleep(1000);
        Console.WriteLine($"Thread {i} end");
        semaphore.Release();
    });
}

上述示例使用SemaphoreSlim实现了在同一时间内只允许3个线程同时执行的功能。首先创建了一个SemaphoreSlim对象,并且初始计数器设置为3。然后使用ThreadPool开启5个新的线程,在每个线程中等待SemaphoreSlim对象信号,当计数器大于0时,线程可以执行,并且计数器会减1。在线程执行完毕后,计数器会加1,以便于其他线程可以继续执行。