欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > C#中的信号

C#中的信号

2024/10/23 15:15:16 来源:https://blog.csdn.net/Lingoesforstudy/article/details/143095664  浏览:    关键词: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); // 初始化计数器为3static 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(),等待所有线程完成当前阶段后,继续执行下一阶段。

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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com