C# Thread挂起线程和恢复线程
前言
众所周知,Thread类中的挂起线程和恢复线程微软已标记过时,因为可能会造成问题
Resume() 恢复当前线程 |
已过时。 Resumes a thread that has been suspended. |
Suspend() 挂起当前线程 |
已过时。 挂起线程,或者如果线程已挂起,则不起作用。 |
其他方式实现
一、ThreadWorkItem
class ThreadWorkItem { public int ThreadManagerId { get; set; } public Thread Thread { get; set; } public string ThreadName { get; set; } public bool Flag { get; set; } public ManualResetEvent ManualResetEvent { get; set; } }
二、C# Thread挂起线程和恢复线程的实现的两种方式
方式1:使用变量开关控制挂起线程和恢复线程,具体代码如下

public class Program { //线程工作集合 private static List<ThreadWorkItem> Works = new List<ThreadWorkItem>(); //方式1:使用变量开关控制挂起线程和恢复线程 private static void Main(string[] args) { ThreadWorkItem wItem = null; Thread t = null; var threadNum = 2; for (int i = 0; i < threadNum; i++) { t = new Thread(o=> { var w = o as ThreadWorkItem; if (w == null) return; while (true) { if (!w.Flag) { Console.WriteLine("我是线程:" + Thread.CurrentThread.Name); Thread.Sleep(1000); continue; } //避免CPU空转 Thread.Sleep(5000); } }); //$ C#6.0语法糖 t.Name = $"Hello I'am 线程:{i}-{t.ManagedThreadId}"; wItem = new ThreadWorkItem { Flag = false, Thread = t, ThreadManagerId = t.ManagedThreadId, ThreadName = t.Name }; Works.Add(wItem); t.Start(Works[i]); } //5秒后允许一个等待的线程继续。当前允许的是线程1 Thread.Sleep(5000); Works[0].Flag = true; Console.WriteLine($"thread-{Works[0].ThreadName} is 暂停"); //5秒后允许一个等待的线程继续。当前允许的是线程0,1 Thread.Sleep(5000); Works[0].Flag = false; Console.WriteLine($"thread-{Works[0].ThreadName} is 恢复"); } }
方式2:使用ManualResetEvent控制挂起线程和恢复线程(推荐);替代Thread类中被微软标记过时的函数(内核模式非混合模式)

public class Program { //线程工作集合 static List<ThreadWorkItem> Works = new List<ThreadWorkItem>(); //方式2:使用ManualResetEvent控制挂起线程和恢复线程(推荐);替代Thread类中被微软标记过时的函数 static void Main(string[] args) { Task.Factory.StartNew(() => { Thread t = null; ThreadWorkItem item = null; for (int i = 0; i < 2; i++) { t = new Thread((o) => { var w = o as ThreadWorkItem; if (w == null) return; while (true) { //阻塞当前线程 w.ManualResetEvent.WaitOne(); Console.WriteLine("我是线程:" + Thread.CurrentThread.Name); Thread.Sleep(1000); } }); t.Name = "Hello,i 'am Thread: " + i; item = new ThreadWorkItem { //线程0,1持续运行,设置true后非阻塞,持续运行。需要手动触发Reset()才会阻塞实例所在当前线程 ManualResetEvent = new ManualResetEvent(true), Thread = t, ThreadManagerId = t.ManagedThreadId, ThreadName = t.Name }; Works.Add(item); t.Start(item); } //5秒后准备暂停一个线程1。线程0持续运行 Thread.Sleep(5000); Console.WriteLine("close..."); Works[1].ManualResetEvent.Reset(); //5秒后恢复线程1;线程0,1持续运行 Thread.Sleep(5000); Console.WriteLine("open..."); Works[1].ManualResetEvent.Set(); //5秒后准备暂停一个线程0。线程1持续运行 Thread.Sleep(5000); Console.WriteLine("close0..."); Works[0].ManualResetEvent.Reset(); //5秒后恢复线程1;线程0,1持续运行 Thread.Sleep(5000); Console.WriteLine("open0..."); Works[0].ManualResetEvent.Set(); }); Console.ReadLine(); } }
三、总结
1.有时候会觉得必须由主线程创建ManualResetEvent实例才能起到作用,实际并不是这样的,上述方式2则证明了这一点。
2.那么AutoResetEvent做不到同样的效果吗?
答:AutoResetEvent 顾名思义,自动Reset()表示重置信号量状态,当前线程中持有WaitOne()就又会被持续阻塞。而ManualResetEvent必须要手动调用Reset()才能重置信号量,这里再解释下Set(),它表明允许一个或多个被同一个ManualResetEvent实例WaitOne()的线程放行。
3.实例化信号量的构造参数是什么意思?
答:信号量非终止状态,如果值为false则表明终止状态,调用WaitOne()方法的时候立即阻塞。设置true可以理解为隐式调用了Set()方法放行一次。
4. ManualResetEvent和AutoResetEvent的区别
答:ManualResetEvent调用Set()允许一个或多个被同一个ManualResetEvent实例WaitOne()的线程放行。
AutoResetEvent调用Set() 只能允许一个线程放行。如果多处使用同一个实例,则需要手动调用多次Set()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
2015-01-12 用提供微软翻译器翻译中创建一个 Web 应用程序
2015-01-12 在 Visual Studio 中使用正则表达式