C#中的信号

        在C#中,信号是用于线程间同步的工具,允许线程通过信号进行等待和通知,以控制并发执行。以下是几种常见的信号工具及其用法:

1. ManualResetEventAutoResetEvent

这两个类都是基于信号量的同步原语。它们都允许线程等待某个信号并决定何时继续执行,区别在于事件被触发后的重置行为:

  • ManualResetEvent:在调用Set()方法后保持信号状态(有信号),除非手动调用Reset()方法清除信号。
  • AutoResetEvent:调用Set()后自动重置为无信号状态,只释放一个等待的线程。
示例:使用ManualResetEvent
using System;
using System.Threading;

class Program
{
    static ManualResetEvent manualEvent = new ManualResetEvent(false); // 初始化为无信号

    static void Main(string[] args)
    {
        Thread t = new Thread(Work);
        t.Start();

        Console.WriteLine("主线程等待一秒钟,然后发出信号...");
        Thread.Sleep(1000);

        // 主线程发出信号
        manualEvent.Set();
        Console.WriteLine("信号已发出,子线程可以继续执行...");
    }

    static void Work()
    {
        Console.WriteLine("子线程启动,等待信号...");
        manualEvent.WaitOne(); // 等待信号
        Console.WriteLine("子线程收到信号,继续执行任务...");
    }
}

注释

  • ManualResetEvent(false)初始化为无信号状态,表示线程在WaitOne()处会阻塞。
  • Set()发出信号后,所有等待的线程都会继续执行。
示例:使用AutoResetEvent
using System;
using System.Threading;

class Program
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false); // 初始化为无信号

    static void Main(string[] args)
    {
        Thread t = new Thread(Work);
        t.Start();

        Console.WriteLine("主线程等待一秒钟,然后发出信号...");
        Thread.Sleep(1000);

        // 主线程发出信号
        autoEvent.Set();
        Console.WriteLine("信号已发出,子线程可以继续执行...");
    }

    static void Work()
    {
        Console.WriteLine("子线程启动,等待信号...");
        autoEvent.WaitOne(); // 等待信号
        Console.WriteLine("子线程收到信号,继续执行任务...");
    }
}

注释

  • AutoResetEvent每次Set()只释放一个等待的线程,且自动重置为无信号状态。

2. SemaphoreSemaphoreSlim

  • Semaphore:用于限制可访问共享资源的线程数量。
  • SemaphoreSlim:是轻量版的Semaphore,但提供了类似的功能,更适合单进程中的线程同步。
示例:使用SemaphoreSlim来限制线程访问资源
using System;
using System.Threading;

class Program
{
    static SemaphoreSlim semaphore = new SemaphoreSlim(2); // 允许最多两个线程同时访问资源

    static void Main(string[] args)
    {
        for (int i = 0; i < 5; i++)
        {
            int threadNum = i;
            Thread t = new Thread(() => AccessResource(threadNum));
            t.Start();
        }
    }

    static void AccessResource(int threadNum)
    {
        Console.WriteLine($"线程 {threadNum} 尝试访问资源...");
        
        semaphore.Wait(); // 尝试获取信号量,如果已经有两个线程持有信号量,则阻塞
        
        Console.WriteLine($"线程 {threadNum} 获得了资源,正在处理...");
        Thread.Sleep(2000); // 模拟资源处理时间
        
        Console.WriteLine($"线程 {threadNum} 释放了资源...");
        semaphore.Release(); // 释放信号量,允许其他线程继续访问
    }
}

注释

  • SemaphoreSlim(2)允许最多两个线程同时访问资源,其余线程会等待。
  • Wait()方法阻塞线程,直到信号量可用。
  • Release()释放信号量,允许其他线程访问资源。

3. CountdownEvent

CountdownEvent用于等待一组操作完成。它初始化时设置一个计数器,当多个线程执行完工作后调用Signal(),减少计数器值,直到计数器归零时,所有等待线程被唤醒。

示例:使用CountdownEvent
using System;
using System.Threading;

class Program
{
    static CountdownEvent countdown = new CountdownEvent(3); // 初始化计数器为3

    static void Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            Thread t = new Thread(DoWork);
            t.Start();
        }

        Console.WriteLine("主线程等待所有子线程完成工作...");
        countdown.Wait(); // 等待计数器归零
        Console.WriteLine("所有子线程工作完成,主线程继续...");
    }

    static void DoWork()
    {
        Console.WriteLine("子线程开始工作...");
        Thread.Sleep(1000); // 模拟工作
        countdown.Signal(); // 通知工作完成,减少计数器
        Console.WriteLine("子线程完成工作...");
    }
}

注释

  • CountdownEvent(3)初始化时设置计数器为3,表示需要3个线程完成工作后主线程才会继续。
  • 每个线程在工作完成后调用Signal(),减少计数器,所有线程完成后countdown.Wait()解除阻塞。

4. Barrier

Barrier用于协调多个线程并发执行,在指定的“阶段”都完成时,所有线程一起继续下一阶段的执行。

示例:使用Barrier来协调线程
using System;
using System.Threading;

class Program
{
    static Barrier barrier = new Barrier(3, (b) =>
    {
        Console.WriteLine($"所有线程已完成第 {b.CurrentPhaseNumber + 1} 阶段。");
    });

    static void Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            Thread t = new Thread(DoWork);
            t.Start();
        }
    }

    static void DoWork()
    {
        Console.WriteLine("线程开始第1阶段...");
        Thread.Sleep(1000); // 模拟工作
        barrier.SignalAndWait(); // 等待所有线程到达第1阶段
        
        Console.WriteLine("线程开始第2阶段...");
        Thread.Sleep(1000); // 模拟工作
        barrier.SignalAndWait(); // 等待所有线程到达第2阶段
    }
}

注释

  • Barrier(3)初始化时设置参与线程数为3。
  • 每个线程在阶段完成时调用SignalAndWait(),等待所有线程完成当前阶段后,继续执行下一阶段。

这些信号工具在多线程编程中非常有用,它们帮助开发者有效地协调和管理线程间的并发执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值