当前位置: 首页 > article >正文

C# 关于闭包与多线程结合使用

开头先看一篇文章:【转】编写高质量代码改善C#程序的157个建议——建议75:警惕线程不会立即启动 - 指间的徘徊 - 博客园d

摘抄:

static int _id = 0;  static void Main()  
{  for (int i = 0; i < 10; i++, _id++)  {  Thread t = new Thread(() =>{  Console.WriteLine(string.Format("{0}:{1}",   Thread.CurrentThread.Name, _id));  });  t.Name = string.Format("Thread{0}", i);  t.IsBackground = true;  t.Start();  }  Console.ReadLine();  
} 

以上代码的可能输出为:
Thread0:2  
Thread4:5  
Thread2:3  
Thread1:3  
Thread5:5  
Thread6:6  
Thread7:7  
Thread8:9  
Thread3:3  
Thread9:10
这段代码的输出从两个方面印证了线程不是立即启动的。

首先,我们看到线程并没有按照顺序启动。在代码逻辑中,前面Start的那个线程也许迟于后Start的那个线程执行。

其次,传入线程内部的ID值,不再是for循环执行中当前的ID值。以Thread9为例,在for循环中,其当前的值为9,而Thread9真正得到执行的时候,ID却已经跳出循环,早已经变为10了。

要让需求得到正确的编码,需要把上面的for循环修改成为一段同步代码:

static int _id = 0;  static void Main()  {  for (int i = 0; i < 10; i++, _id++)  {  NewMethod1(i, _id);  }  Console.ReadLine();  }  private static void NewMethod1(int i, int realTimeID)  {  Thread t = new Thread(() =>{  Console.WriteLine(string.Format("{0}:{1}",   Thread.CurrentThread.Name, realTimeID));  });  t.Name = string.Format("Thread{0}", i);  t.IsBackground = true;  t.Start();  }  
} 

以上代码输出:
Thread0:0  
Thread3:3  
Thread1:1  
Thread2:2  
Thread5:5  
Thread4:4  
Thread6:6  
Thread7:7  
Thread8:8  
Thread9:9
可以看到,线程虽然保持了不会立即启动的特点,但是传入线程的ID值,由于在for循环内部变成了同步代码,所以能够正确传入。

 疑问:

上面这篇文章说的在for循环内部变成了同步代码是是什么意思,原来不也是for循环吗?

解答:

第一段

所有线程捕获的是同一个 _id 变量(闭包特性)。当线程真正执行时,_id 可能已经被循环多次递增(例如,Thread0 启动时 _id 可能已经是 10)。

输出中 _id 的值是混乱的(如 Thread9:10),因为线程执行时 _id 已经变成循环结束后的值。

第二段

通过方法参数 realTimeID 传递 _id 的当前值(值传递而非引用捕获)。

每个线程的 realTimeID 是调用 NewMethod1 时传入的 _id 的瞬时值(值类型复制),因此即使 _id 后续被修改,线程内部的值也不会变。

虽然线程启动顺序仍不确定,但每个线程的 realTimeID 是正确的(如 Thread0:0, Thread1:1

http://www.lryc.cn/news/2394445.html

相关文章:

  • LangFuse:开源LLM工程平台的革新实践
  • 新视角!经济学顶刊QJE用文本分析探究新技术扩散
  • 微信小程序返回上一页监听
  • 5月31日day41打卡
  • “粽”览全局:分布式系统架构与实践深度解析(端午特别版)
  • STM32G4 电机外设篇(一) GPIO+UART
  • 代理IP在云计算中的应用:技术演进与场景实践
  • Lua 的速度为什么比 Python 快
  • 【iOS】方法交换
  • 跑步相关术语解释
  • 数据结构:线性表的基本操作与链式表达
  • C++:设计模式--工厂模式
  • 【前端优化】使用speed-measure-webpack-plugin分析前端运行、打包耗时,优化项目
  • 国产化Excel处理组件Spire.XLS教程:如何使用 C# 将 Excel(XLS 或 XLSX)文件转换为 PDF
  • B3623 枚举排列(递归实现排列型枚举)
  • vue-08(使用slot进行灵活的组件渲染)
  • Fine Pruned Tiled Light Lists(精细删减的分块光照列表)
  • 2025-5-29-C++ 学习 字符串(3)
  • openresty+lua+redis把非正常访问的域名加入黑名单
  • 使用Mathematica绘制随机多项式的根
  • IEEE PRMVAI 2025 WS 26:计算机视觉前沿 Workshop 来袭!
  • 360浏览器设置主题
  • 最卸载器——Geek Uninstaller 使用指南
  • leetcode216.组合总和III:回溯算法中多条件约束下的状态管理
  • 应急响应靶机-web3-知攻善防实验室
  • 【基于SpringBoot的图书购买系统】Redis中的数据以分页的形式展示:从配置到前后端交互的完整实现
  • Jupyter MCP服务器部署实战:AI模型与Python环境无缝集成教程
  • PMO价值重构:从项目管理“交付机器”到“战略推手”
  • 如何成为一名优秀的产品经理
  • [SLAM自救笔记0]:开端