C# 不用lock写一个多线程程序

多线程并发

    当一段代码有可能被不止一个线程同时访问时,且存在共享资源(变量、文件句柄等),可能出现并发冲突。发生并发冲突时如果不加锁,程序的行为是不可预测的。而加锁本身又是一件麻烦事,弄不好会出现死锁,死锁时程序卡在那既没有异常也没有日志,找问题都无从下手。

    C#中通常会使用 lock 来加锁,这里应严格避免锁静态对象(如 lock(type)),避免 lock(this),这种锁的粒度都太大,容易出现死锁。

多线程程序不加锁的方法

第一,bool 类型是线程安全的,不需要锁

第二,整形, DateTime 类型可以用Interlocked

long lastTicks= DateTime.Now.Ticks;private void multiThreadMethod()
{var l = Interlocked.Read(ref lastTicks);var lastTime = new DateTime(l);//读取上一时刻.//do work...Interlocked.Exchange(ref lastTicks, DateTime.Now.Ticks);//更新上一时刻.
}

 第三,多使用ConcurrentQuere, ConcurrentDictionary

 一个典型的数采驱动程序

    数采驱动通常需要做 接收-处理-转发 三步,为避免阻塞接收,接收后应该入队,由单独的线程完成处理、转发工作。可以设计两个类Driver, MessageHandler,Driver接受数据,MessageHandler入队处理后返回给Driver,再有Driver发送出去。

    Driver代码要关键要保持与数据源的链接,断开后能够自动重连,这部分大概率要有bool 变量在表示链接状态,有lastConnect来记录上次连接成功/数据更新的时间,以便在连接断开或数据不动多长时间后自动重连,收到到数据后入队到MessageHandler处理,并把MessageHandler返回的数据发送出去。

    下面的MessageHandler代码中有三个关键点,

  • 用ConcurrentQuere,出队/入队时避免使用lock;
  • Thread的标准写法,即有一个quitFlag 布尔变量来控制线程的退出,因为线程只有在无事可做时才能退出,不要试图从外部让线程退出;
  • Close 线程退出后,还要把队列中未处理的部分处理完。
public class MessageHandler
{ConcurrentQueue<string> queue;Thread thread;bool quitFlag = false;const int BATCH_SIZE = 100;//每次连续发送数据的数量.public MessageHandler(){queue = new ConcurrentQueue<string>();}public event Action<List<MyDataType>> OnDataArrive;        //有新数据.public void Enqueue(string msg){queue.Enqueue(msg);}public void Open(){if (thread == null){quitFlag = false;thread = new Thread(doWork);thread.Start();}}private void doWork(){while (!quitFlag){int i = 0;List<MyDataType> datas = new List<MyDataType>();while (queue.Count > 0 && i < BATCH_SIZE){if (queue.TryDequeue(out string msg)){doWorkBody(msg, datas);i++;}}if (datas.Count > 0){OnDataArrive?.Invoke(datas);}Thread.Sleep(50);}}private void doWorkBody(string msg, List<MyDataType> datas){try{var dataPackage = JsonConvert.DeserializeObject<DataPackage>(msg);foreach (var dataItem in dataPackage.Data){datas.Add(new MyDataType(){//从MQTT payload中得到数据});}}catch(Exception ex){Logger.Error(ex, $"解析 {msg} 出错", logSource);}}public void Close(){//退出线程quitFlag = true;if (thread != null){thread.Join();thread = null;}List<MyDataType> datas = new List<MyDataType>();while (queue.Count > 0){if (queue.TryDequeue(out string msg)){doWorkBody(msg, datas);}}//处理最后一批数据if (datas.Count > 0){OnDataArrive?.Invoke(datas);}}
}

    

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

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

相关文章

嵌入式全栈开发学习笔记---C语言笔试复习大全15

目录 指针运算 笔试题17 思考&#xff1a;*px、*px和(*px)的区别&#xff01; 笔试题18 补充命令8&#xff1a;“cd ..”退回到上一级目录 补充命令9&#xff1a;“man 3 函数名”可以查看库函数的原型 const 修饰指针是什么意思&#xff1f;&#xff08;笔试重点&#…

浅谈var let const

浅谈var let const var 在ES5中&#xff0c;顶层对象的属性和全局变量是等价的&#xff0c;用var声明的变量既是全局变量&#xff0c;也是顶层变量 var a 10; console.log(window.a) // 10使用var声明的变量存在变量提升的情况 console.log(a) // undefined var a 20// 编…

【C++语言】模板

当谈到C中的模板时&#xff0c;我们在谈论一种强大的工具&#xff0c;它允许程序员编写通用的代码&#xff0c;而不必为特定类型编写多个版本。模板使得编写可重用和灵活的代码变得更加容易&#xff0c;因为它们允许您编写与任何数据类型一起使用的通用算法和数据结构。 什么是…

C++入门指南(上)

目录 ​编辑 一、祖师爷画像 二、什么是C 三、C发展史 四、C在工作领域的应用 1. 操作系统以及大型系统软件开发 2. 服务器端开发 3. 游戏开发 4. 嵌入式和物联网领域 5. 数字图像处理 6. 人工智能 7. 分布式应用 五、如何快速上手C 一、祖师爷画像 本贾尼斯特劳斯…

第二届“盘古石杯”全国电子数据取证大赛wp

服务器取证 先对网站进行重构 [rootstudy ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 643626ab3d8b mattermost/mattermost-pre…

Linux部署

先把需要的东西准备好&#xff1a; 第一步解压tomcat&#xff1a; tar -zxvf apache-tomcat-8.5.20.tar.gz 第二步解压jdk: tar -zxvf jdk-8u151-linux-x64.tar.gz 第三步配置Java环境变量&#xff1a; vim /etc/profile 把下面代码放进去&#xff1a; export JAVA_HOME/root…

dell服务器安装ubuntu18.04桌面版教程

目录 一、制作U盘启动盘 1.镜像下载地址&#xff1a; 2.制作U盘启动盘 二、服务器进入bios一系列设置 1.插入U盘启动盘 2.开机过程按F11键&#xff0c;进入Boot Manager &#xff0c;点击 3.点击点击One-shot BIOS Boot Menu 4.进入boot menu ,找到U盘&#xff08;一般…

react18【系列实用教程】useContext —— Context 机制实现越层组件传值 (2024最新版)

什么是 Context 机制&#xff1f; Context 机制是 react 实现外层组件向内层组件传值的一种方案&#xff0c;父组件可以向其内部的任一组件传值&#xff0c;无论是子组件还是孙组件或更深层次的组件。 实现步骤 1.使用createContext方法创建一个上下文对象 Ctx 2.在顶层组件中通…

基于springboot的校园闲置物品交易系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于springboot的校园闲置物品交易系统,…

云南区块链商户平台:抓包技术自制开票工具(三)

前言 上节我们将登录的流程梳理完毕了&#xff0c;来到了本章重点&#xff0c;既然开发票就肯定要有以下参数&#xff1a; 原工具不支持识别历史记录&#xff0c;对于我们的小商店来说&#xff0c;开票的公司基本就是固定的几个&#xff0c;如果提供下拉支持选择将会大大降低…

Java高并发场景(银行转账问题)

最近面试问到了银行转账的高并发问题&#xff0c;回答的不是很理想&#xff0c;小编整理了下&#xff0c;题目大概如下&#xff1a; 有一张银行账号表&#xff08;银行账号字段、金额字段&#xff09;&#xff0c;A账号要给B账号转账&#xff0c;A扣款&#xff0c;B收款&#x…

牛客_非技术快速入门_题目总结

牛客_非技术快速入门_题目总结 SQL29 计算用户的平均次日留存率 描述 题目&#xff1a;现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。 示例&#xff1a;question_practice_detail id device_id quest_id result date 1 2138 111 wron…

@Transaction注解详情解释

概念&#xff1a; Transactional注解是Spring框架提供的一个用于声明式事务管理的注解&#xff0c;方便我们管理事务&#xff0c;保证数据的一致性与可靠性。 事务4个基本特性&#xff1a; 原子性&#xff1a;一个事务要不全部&#xff08;sql&#xff09;执行&#xff1b;要不…

Python图形界面(GUI)Tkinter笔记(四):控件的定位(2)

Tkinter(GUI)设计图形界面时有三种控件的包装方法去定位各控件在窗口(父容器、根窗口)上的位置。 【1】pack()方法:用方位来定位位置,类似于Word文档中的文字对齐方式。 【2】grid()方法:用二维表格式的坐标值定位,类似于EXCEL单元格坐标。 【3】place()方法:用窗口…

华为ce12800文件保存python之sftp

##CE12800 交换机上配置 [*SSH Server] dsa local-key-pair create [*SSH Server] sftp server enable [*SSH Server] ssh user adminadmin authentication-type password [*SSH Server] ssh user adminadmin service-type sftp [*SSH Server] ssh user adminadmin sftp-direc…

【机器学习】 技术栈和开发环境搭建

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 博客目录 技术栈编程语言库框架编辑器项目IDE …

linux下的进程通信

进程通信 进程为什么需要通信呢&#xff1f;进程通信的技术背景进程通信本质 进程通信分类管道匿名管道pipe匿名管道原理管道特点 命名管道创建命名管道命名管道原理 System V IPC管道与 System V的区别共享内存函数ftok()shmget() shmat()shmdt()shmctl()删除共享内存System V…

探索数据结构(让数据结构不再成为幻想)

目录 什么是数据结构 数据与结构 什么是算法 复杂度分析 时间复杂度与空间复杂度 时间复杂度 思考&#xff1a; 空间复杂度 常数阶O(1) 对数阶O(logn) 线性阶O(n) 以下为空间复杂度为O(n) 线性对数阶O(nlogn) 平方阶O(n) 指数阶O(2^n) 什么是数据结构 数据结构…

WHAT - CSS Animationtion 动画系列(二)

目录 一、循环波浪二、关键帧呼应三、关键帧顺接四、利用 transform-origin 做拉伸五、大元素可拆分多个小元素联动六、预留视觉缓冲七、随机感&#xff1a;动画周期设置八、抛物线&#xff1a;两个内外div实现x和y向量运动 今天我们主要学习动画实现要素。 一、循环波浪 利用…

类加载机制(双亲委派机制)

文章目录 JVM的作用是什么双亲委派机制加载流程 JVM的作用是什么 我们运行Java程序时&#xff0c;要安装JDK&#xff0c;JDK包含JVM&#xff0c;不同环境的JDK都是不同的。 Java 代码在编译后会形成 class 的字节码文件&#xff0c;该字节码文件通过 JVM 解释器&#xff0c;生…