[原创][3]探究C#多线程开发细节-“用ConcurrentQueue<T>解决多线程的无顺序性的问题“

[简介]
常用网名: 猪头三
出生日期: 1981.XX.XX
QQ: 643439947
个人网站: 80x86汇编小站 https://www.x86asm.org
编程生涯: 2001年~至今[共22年]
职业生涯: 20年
开发语言: C/C++、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python
开发工具: Visual Studio、Delphi、XCode、Eclipse、C++ Builder
技能种类: 逆向 驱动 磁盘 文件
研发领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全/macOS应用软件安全
项目经历: 磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测

[序言]
经过上一篇文章([原创][2]探究C#多线程开发细节-“线程的无顺序性“-CSDN博客), 得知在不干预的情况下, 默认运行是无顺序的. 那么这样特性, 对程序的运行来说, 是好还是坏呢? 其实无顺序没有好坏之说, 只跟程序功能的业务需求有关系. 当一个业务需求也可以说是功能, 需要多线程的无顺序特性, 那么在写代码的过程中就不要干预它. 如果业务需求对顺序有严格要求, 那么在编写多线程时, 就要适当得干预了.

[到底什么需求和场合需要控制多线程的运行顺序呢?]
这里举例一个最常见的场合: 比如有一个10G的文件, 程序创建了10个线程来读取内容, 每个线程分别依次读取1G内容(0号线程  读取的范围是0~1G, 1号线程 读取的范围1~2G, 2号线程 读取的范围是2~3G, 依次类推), 然后每个线程读取内容完毕之后, 就在程序界面上显示. 

[上面的场合, 如果不控制多线程的运行顺序时, 会发生什么现象呢?]
出现的现象就是: 假设当1号线程最先读取完1~2G范围的内容, 该线程就马上在界面显示. 当显示完成之后, 0号线程才完成读取0~1G范围的内容并在界面显示. 这样内容就错乱了.

这里把刚才抽象的描述实例化: 假设一个文件有10个字, "我爱CSDN编程网站". 每1个线程分别控制1个字的读取和显示, 形成如下关系:

0号线程 读取并显示 "我"
1号线程 读取并显示 "爱"
2号线程 读取并显示 "C"
3号线程 读取并显示 "S"
4号线程 读取并显示 "D"
5号线程 读取并显示 "N"
6号线程 读取并显示 "编"
7号线程 读取并显示 "成"
8号线程 读取并显示 "网"
9号线程 读取并显示 "站"

如果不加以干预的话, 界面上最终显示出来的内容, 有可能是 "编爱CDSN我网站程" 这样错乱的效果.

[那么如何解决这样的问题呢?]
遇到的这样问题, 就需要一个叫ConcurrentQueue<T>类,它是多线程安全的并提供先进先出(FIFO)的数据结构操作方法. 现在看看如何利用ConcurrentQueue<T>类来强制把无顺序的多线程改变成有顺序的.
1> 在使用for循环创建线程的时候, 同时也把线程的编号有序的存放到ConcurrentQueue<T>.
2> 假如当3号线程提前完成了文件内容的读取, 在返回给界面显示之前, 先判断2号线程是否完成, 如果2号线程没有完成, 那么3号线程就原地等待, 直到2号线程把内容读取完毕并在界面显示完成之后, 它才能在界面显示
步骤2是非常关键的逻辑, 这里仅仅是举例3号线程与2号线程的关系, 依次类推, 其他线程也有这样的等待关系.
3> 如何判断2号线程是否完成内容读取与内容显示?
很简单, 直接从ConcurrentQueue<T>的队列头部获取线程编号即可. 如果队列头部的编号为"3",就表示"2"号线程已经完成所有工作任务并轮到3号线程开始干活了.

[下面是一套完整的代码]
这套代码是入门级的, 主要是多线程实验演示. 如果哪个朋友一眼看出, 有更好的代码实现, 说明你是高手了.  如果看不出来, 也不要紧. 后期还有更多的讲解并且释放出更优秀的多线程代码让大家学习.

   public partial class Form_Main : Form{private ConcurrentQueue<int> mpr_cq_ThreadIndex = new ConcurrentQueue<int>();public class Thread_Run{public int mpu_int_ThreadIndex;private Action<int> mpr_action_UpdateWaiteInfo;private ConcurrentQueue<int> mpr_cq_ThreadIndex;public Thread_Run(Action<int> action_param_UpdateWaiteInfo, ref ConcurrentQueue<int> cq_param_ThreadIndex){mpr_action_UpdateWaiteInfo = action_param_UpdateWaiteInfo;mpr_cq_ThreadIndex = cq_param_ThreadIndex;}public int mpu_fun_ShowIndex(){return mpu_int_ThreadIndex;}public void mpu_pro_StartThread(){Thread class_Thread = new Thread(Thread_Exe);class_Thread.Start();}private void Thread_Exe(){int int_Dq_ThreadIndex;// 核心重点: N号线程等待N-1线程是否完成任务while (true){if (mpr_cq_ThreadIndex.TryPeek(out int_Dq_ThreadIndex) && int_Dq_ThreadIndex == mpu_int_ThreadIndex){//调用委托方法来更新UImpr_action_UpdateWaiteInfo?.Invoke(mpu_int_ThreadIndex);mpr_cq_ThreadIndex.TryDequeue(out _);break;}Thread.Sleep(5);}}}// End Thread_Run()public Form_Main(){InitializeComponent();}public void mpu_pro_UpdateWaiteInfo(int int_param_ThreadIndex){if (InvokeRequired){this.Invoke((MethodInvoker)delegate {lb_WaitInfo.Text += (Environment.NewLine + string.Format("{0} 号线程已经跑到终点.", int_param_ThreadIndex));});}}private void Bn_StartThread_Click(object sender, EventArgs e){// 启动10个线程for (int int_Index = 0; int_Index < 10; int_Index++){mpr_cq_ThreadIndex.Enqueue(int_Index);Thread_Run class_ThreadRun = new Thread_Run(mpu_pro_UpdateWaiteInfo, ref mpr_cq_ThreadIndex);class_ThreadRun.mpu_int_ThreadIndex = int_Index;class_ThreadRun.mpu_pro_StartThread();}}}


[总结]
如果你们能按照源码把程序运行起来, 并且理解了本文章的内容, 那么是一个很大的进步. 这做这个代码实验的时候, 如遇到问题, 可在下面留言, 我会一一针对性的回复.


[程序截图]
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/186797.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity随笔1 - 安卓打包JDK not found

今天遇到一个很奇怪的事情&#xff0c;之前可以正常打安卓包&#xff0c;但是突然报错如下&#xff1a; 提示很明显&#xff0c;找不到JDK了。可是我在下载Unity的时候明明安装了所有需要的组件&#xff0c;为什么今天突然不行。 看了眼Unity hub里面&#xff0c;没问题。 那就…

MySQL表的查询、更新、删除

查询 全列查询 指定列查询 查询字段并添加自定义表达式 自定义表达式重命名 查询指定列并去重 select distinct 列名 from 表名 where条件 查询列数据为null的 null与 (空串)是不同的&#xff01; 附&#xff1a;一般null不参与查询。 查询列数据不为null的 查询某列数据指定…

概念理论类-k8s :架构篇

转载&#xff1a;新手通俗易懂 k8s &#xff1a;架构篇 Kubernetes&#xff0c;读音是[kubə’netis]&#xff0c;翻译成中文就是“库伯奈踢死”。当然了&#xff0c;也可以直接读它的简称&#xff1a;k8s。为什么把Kubernetes读作k8s&#xff0c;因为Kubernetes中间有8个字母…

ssm+java车辆售后维护系统 springboot汽车保养养护管理系统+jsp

以前汽车维修人员只是在汽车运输行业中从事后勤保障工作,随着我国经济的发展,汽车维修行业已经从原来的从属部门发展成了如今的功能齐备的独立企业。这种结构的转变,给私营汽修企业和个体汽修企业的发展带来了契机,私营企业和个体维修企业的加入也带动了整个汽修行业的整体水平…

SSM校园组团平台系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 校园组团平台系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

Docker 下载加速

文章目录 方式1&#xff1a;使用 网易数帆容器镜像仓库进行下载。方式2&#xff1a;配置阿里云加速。方式3&#xff1a;方式4&#xff1a;结尾注意 Docker下载加速的原理是&#xff0c;在拉取镜像时使用一个国内的镜像站点&#xff0c;该站点已经缓存了各个版本的官方 Docker 镜…

《金融科技行业2023年专利分析白皮书》发布——科技变革金融,专利助力行业发展

金融是国民经济的血脉&#xff0c;是国家核心竞争力的重要组成部分&#xff0c;金融高质量发展成为2023年中央金融工作的重要议题。《中国金融科技调查报告》中指出&#xff0c;我国金融服务业在科技的助力下&#xff0c;从1.0时代的“信息科技金融”、2.0时代的“互联网金融”…

传统算法: Pygame 实现深度优先搜索(DFS)

使用 Pygame 模块实现了深度优先搜索(DFS)的动画演示。首先,它通过邻接矩阵表示了一个图的结构,其中每个节点表示一个字符,每个字符的邻居表示与之相邻的节点。然后,通过深度优先搜索算法递归地访问所有节点,过程中通过动画效果可视化每一步的变化。每次访问一个节点,该…

Goby 漏洞发布| CrushFTP as2-to 认证权限绕过漏洞(CVE-2023-43177)

漏洞名称&#xff1a; CrushFTP as2-to 认证权限绕过漏洞&#xff08;CVE-2023-43177&#xff09; English Name&#xff1a;CrushFTP as2-to Authentication Permission bypass Vulnerability (CVE-2023-43177) CVSS core: 9.8 影响资产数&#xff1a; 38695 漏洞描述&…

什么是透明加密技术?透明加密有哪些优势?

透明加密技术是一种特殊的加密方法&#xff0c;它在用户毫不知情的情况下对数据进行加密和解密&#xff0c;保障了数据的安全性。用户在使用这种加密技术时&#xff0c;无需改变他们的日常操作习惯&#xff0c;加密和解密过程在后台自动进行&#xff0c;使得用户在享受数据安全…

C语言--有三个字符串,要求找出其中长度最大的那一个

一.题目描述 有三个字符串&#xff0c;要求找出其中长度最大的那一个。 比如&#xff1a;输入三个字符串是&#xff1a; 第一个字符串:hello 第二个字符串&#xff1a;worldasd 第三个字符串&#xff1a;abcd 输出&#xff1a;最长的字符串是&#xff1a;worldasd 二.思路分析…

webpack优化打包速度

webpack打包速度太慢 优化 1.多线程打包 js压缩和loader 2.优化启动速度 hard-source-webpack-plugin 3.删除无用的 分析类插件 4.DllPlugin通道打包 1.webpack多线程打包 loader loader 使用 thread-loader 将他放置你要使用的loader前面就行&#xff0c;不过这个lorder例如s…

基于51单片机的数字电压表设计

1&#xff0e;设计任务 利用AT89C51单片机为核心控制元件,设计一个简易的数字电压表&#xff0c;设计的系统实用性强、操作简单&#xff0c;实现了智能化、数字化。 基本要求&#xff1a;利用单片机AT89C51设计数字电压表&#xff0c;能对模拟信号进行检测&#xff0c;能将所…

STC15-串口通信打印输出数据printf函数与sprintf函数

STC15-串口通信打印输出数据printf函数与sprintf函数 1.打印输出数据有二种printf函数与sprintf函数&#xff0c;不同之处有&#xff1a;&#xff08;1&#xff09;函数的声明不同&#xff08;2&#xff09;函数的功能不同&#xff08;3&#xff09;用法举例 该问题引用百度知道…

2的幂运算

2的幂 描述 : 给你一个整数 n&#xff0c;请你判断该整数是否是 2 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 如果存在一个整数 x 使得 n 2x &#xff0c;则认为 n 是 2 的幂次方。 题目 : LeetCode 231.2的幂 : 231. 2 的幂 分…

SpringBoot中的部分注解

1.SpringBoot/spring SpringBootApplication: 包含Configuration、EnableAutoConfiguration、ComponentScan通常用在主类上&#xff1b; Repository: 用于标注数据访问组件&#xff0c;即DAO组件&#xff1b; Service: 用于标注业务层组件&#xff1b; RestController: 用…

中国毫米波雷达产业分析3——毫米波雷达市场分析(四、五、六)

四、康养雷达市场 &#xff08;一&#xff09;市场背景 1、政府出台系列政策提升智慧健康养老产品供给和应用 康养雷达是一种以老年人为主要监测对象&#xff0c;可以实现人体感应探测、跌倒检测报警、睡眠呼吸心率监测等重要养老监护功能的新型智慧健康养老产品。 随着我国经…

商家门店小程序怎么做?门店小程序的优势和好处

生活服务类商家在当前数字化时代&#xff0c;越来越认识到门店小程序的重要性。门店小程序不仅为商家提供了一个在线展示的窗口&#xff0c;更为其打造了一个与消费者直接互动的平台。有了门店小程序&#xff0c;商家可以更加便捷地管理商品信息、订单流程&#xff0c;同时还能…

HX3002入耳检测光感驱动调试-感0x08 寄存器溢出,不变化错误问题解决方法

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 读取光感0x08 寄存器溢出,不变化错误问题?原因 原因:没有读取到0x08数据,没有读0x…

C语言二叉树与堆的实现(一)

目录 二叉树 二叉树的分类&#xff08;目前只谈两种&#xff09; 满二叉树 完全二叉树 二叉树的性质&#xff08;其余的可以自己总结&#xff09; 选择练习 二叉树的存储结构 顺序存储方式 链式存储方式 一种完全二叉树&#xff1a;堆 堆的概念 堆的性质 建堆的时…