C# 线程基础之 线程同步
线程同步的手段很多
lock 是通过内存索引块 0 1 切换 进行互斥的实现
互斥量 信号量 事件消息 其实意思就是 一个 标记量
通过这个标记 来进行类似的互斥手段
具体方式的分析 代码在后
1.互斥量 Mutex 作用 非常类似lock 一个Mutex 名称来代替 lock的引用对象
2.信号量 SemaphoreSlim 作用 同时访问同一个资源的线程数量 跨程序同步的场景下可以使用 混合模式
3.事件标识 AutoResetEvent 作用 类似lock 通过 waitone 阻塞与 set 通行 但只有一个线程可用标识
4.事件标识 ManualResetEventSlim 通过 set 通行 reset 设置阻塞 wait 阻塞 多个线程可用标识
5.事件标识 CountdownEvent 作用 限制指定次数信号量 达到后通行
6. SpinWait 自选锁 混合模式
7. ReaderWriterLockSlim 读写锁
互斥量 Mutex ReleaseMutex 测试先在项目路径cmd用命令行dotnet run 执行 然后在看断点
class Program
{static void Main(string[] args){const string MutexName = "testMutex";using (var m = new Mutex(false, MutexName)){if (!m.WaitOne(TimeSpan.FromSeconds(3), false)){Console.WriteLine("未捕获到互斥量");}else{Console.WriteLine("执行逻辑");Console.ReadLine();//释放互斥量m.ReleaseMutex();}}}
}

信号量 SemaphoreSlim 设置数量为4 循环中执行3次 主线程执行一次 发现主线程没执行
必须释放信号量 才可以 满足 最大执行数保存在4以内
class Program
{static void Main(string[] args){for (int i = 1; i <= 3; i++){string threadName = "Thread " + i;var t = new Thread(() => SemaphoreS(threadName, 2));t.Start();}var t1 = new Thread(() => SemaphoreS("4", 2));t1.Start();}static SemaphoreSlim _semaphore = new SemaphoreSlim(3);static void SemaphoreS(string name, int seconds){Console.WriteLine("{0} 开始", name);_semaphore.Wait();Console.WriteLine("{0} 执行", name);Thread.Sleep(TimeSpan.FromSeconds(seconds));Console.WriteLine("{0} 完成", name);//释放信号量//_semaphore.Release();}
}

AutoResetEvent 设置俩个 事件标识 通过set 畅通信号 waitone 阻塞信号
于是可以看到 子线程1》主线程2》子线程2 =子线程3》主线程3
class Program
{static void Main(string[] args){var t = new Thread(() => Process());t.Start();Console.WriteLine("主线程过程1");_workerEvent.WaitOne();Console.WriteLine("主线程过程2");_mainEvent.Set();_workerEvent.WaitOne();Console.WriteLine("主线程过程3");Console.ReadKey();}private static AutoResetEvent _workerEvent = new AutoResetEvent(false);private static AutoResetEvent _mainEvent = new AutoResetEvent(false);static void Process(){Console.WriteLine("子线程过程1");_workerEvent.Set();_mainEvent.WaitOne();Console.WriteLine("子线程过程2");Console.WriteLine("子线程过程3");_workerEvent.Set();}
}

但是如果使用多个子线程发现 其实只有1个子线程能够识别这个 标识

ManualResetEventSlim 为了解决上诉 1个线程使用标识的问题 俩个线程测试通过 主线程set通行
子线程中reset阻塞 并且wait等待 ManualResetEvent 用waitone
class Program
{static void Main(string[] args){var t = new Thread(() => Process(1));t.Start();var t1 = new Thread(() => Process(2));t1.Start();Console.WriteLine("主线程过程1");_mainEvent.Set();Thread.Sleep(3);Console.WriteLine("主线程过程2");_mainEvent.Set();Thread.Sleep(3);Console.WriteLine("主线程过程3"); _mainEvent.Set();Console.ReadKey();}private static ManualResetEvent _mainEvent = new ManualResetEvent(false);static void Process(int i){_mainEvent.WaitOne();Console.WriteLine(i+"子线程过程1");_mainEvent.Reset();_mainEvent.WaitOne();Console.WriteLine(i + "子线程过程2");_mainEvent.Reset();_mainEvent.WaitOne();Console.WriteLine(i + "子线程过程3");}
}
class Program
{static void Main(string[] args){var t = new Thread(() => Process(1));t.Start();var t1 = new Thread(() => Process(2));t1.Start();Console.WriteLine("主线程过程1");_mainEvent.Set();Thread.Sleep(3);Console.WriteLine("主线程过程2");_mainEvent.Set();Thread.Sleep(3);Console.WriteLine("主线程过程3"); _mainEvent.Set();Console.ReadKey();}private static ManualResetEventSlim _mainEvent = new ManualResetEventSlim(false);static void Process(int i){_mainEvent.Wait();Console.WriteLine(i+"子线程过程1");_mainEvent.Reset();_mainEvent.Wait();Console.WriteLine(i + "子线程过程2");_mainEvent.Reset();_mainEvent.Wait();Console.WriteLine(i + "子线程过程3");}
}

CountdownEvent 达到指定次数 继续通行 否则 wait阻塞 signal记录次数 Dispose 释放
class Program
{static void Main(string[] args){Console.WriteLine("俩个线程");var t1 = new Thread(() => StartThread("线程1", 4));var t2 = new Thread(() => StartThread("线程2", 8));t1.Start();t2.Start();_countdown.Wait();Console.WriteLine("结束");_countdown.Dispose();Console.ReadKey();}static CountdownEvent _countdown = new CountdownEvent(2);//指定次数 如果设置3 那么 结束不会打印一直会阻塞static void StartThread(string message, int seconds){Thread.Sleep(TimeSpan.FromSeconds(seconds));Console.WriteLine(message);_countdown.Signal();//记录次数执行一次就会+1 如果不设置 那么不达到指定次数 也会一直 wait阻塞}
}
SpinWait 自选锁 混合模式 用户模式 短时间循环等待 然后行不通即切换上下文 内核模式阻塞
class Program
{static void Main(string[] args){var t1 = new Thread(UserModeWait);//用户模式var t2 = new Thread(HybridSpinWait);//混合模式Console.WriteLine("用户模式");t1.Start();Thread.Sleep(1);_isOKUser = true;Console.WriteLine("混合模式");t2.Start();Thread.Sleep(5);_isOKSpin = true;Console.ReadKey();}static volatile bool _isOKUser = false; //volatile 修饰多个线程访问 最新值 存在内存中static volatile bool _isOKSpin = false;static void UserModeWait(){while (!_isOKUser){Console.Write("-不ok-");}Console.WriteLine();Console.WriteLine("用户模式OK");}static void HybridSpinWait(){var w = new SpinWait(); //先用户模式占用cpu资源等待循环9次 若还没等到执行通行 那么切换上下文 内核模式 阻塞 while (!_isOKSpin){w.SpinOnce();Console.WriteLine("混合模式上下文切换"+w.NextSpinWillYield);}Console.WriteLine("混合模式OK");}
}

ReaderWriterLockSlim 读写锁 就是 读可共享锁 写是互斥锁 当断点设置在写锁的过程中 可以看见 读取的时候被阻塞了
class Program
{static void Main(string[] args){new Thread(Read) { IsBackground = true }.Start();new Thread(Read) { IsBackground = true }.Start();new Thread(Read) { IsBackground = true }.Start();new Thread(() => Write("Thread 1")) { IsBackground = true }.Start();new Thread(() => Write("Thread 2")) { IsBackground = true }.Start();Thread.Sleep(TimeSpan.FromSeconds(10));Console.ReadKey();}static ReaderWriterLockSlim _rw = new ReaderWriterLockSlim();static Dictionary<int, int> _items = new Dictionary<int, int>();static void Read(){Console.WriteLine("读取");while (true){try{_rw.EnterReadLock();foreach (var key in _items.Keys){Console.WriteLine(Thread.CurrentThread.ManagedThreadId+ "读取字典"+key);Thread.Sleep(TimeSpan.FromSeconds(0.1));}}finally{_rw.ExitReadLock();}}}static void Write(string threadName){while (true){try{int newKey = new Random().Next(5);_rw.EnterUpgradeableReadLock();if (!_items.ContainsKey(newKey)){try{_rw.EnterWriteLock();_items[newKey] = 1;Console.WriteLine("{0}添加字典 {1}", threadName, newKey);}finally{_rw.ExitWriteLock();}}Thread.Sleep(TimeSpan.FromSeconds(0.1));}finally{_rw.ExitUpgradeableReadLock();}}}
}

相关文章:
C# 线程基础之 线程同步
线程同步的手段很多 lock 是通过内存索引块 0 1 切换 进行互斥的实现 互斥量 信号量 事件消息 其实意思就是 一个 标记量 通过这个标记 来进行类似的互斥手段 具体方式的分析 代码在后 1.互斥量 Mutex 作用 非常类似lock 一个Mutex 名称来代替 lock的引用对象 2.信号量 Semaph…...
[c语言日寄]c语言也有“回”字的多种写法——整数交换的三种方式
大家好啊,在今天的快乐刷题中,我们遇到了这样一道题目: 题目 写出 三种不同方式的 交换两个整数变量的 函数 交换变量的三种解法 常规方式 想要交换两个变量很简单,第一种方式就是新建一个临时变量,具体流程如下&…...
RocketMQ 知识速览
文章目录 一、消息队列对比二、RocketMQ 基础1. 消息模型2. 技术架构3. 消息类型4. 消费者类型5. 消费者分组和生产者分组 三、RocketMQ 高级1. 如何解决顺序消费和重复消费2. 如何实现分布式事务3. 如何解决消息堆积问题4. 如何保证高性能读写5. 刷盘机制 (topic 模…...
优化 Azure Synapse Dedicated SQL Pool中的 SQL 执行性能的经验方法
在 Azure Synapse Dedicated SQL Pool中优化 SQL 执行涉及了解底层体系结构(例如分布和分区)、查询优化(例如避免不必要的子查询和联接),以及利用具体化视图和 PolyBase 等工具进行高效数据加载。 1.有效使用分布和分…...
详解英语单词“pro bono”:公益服务的表达(中英双语)
中文版 详解英语单词“pro bono”:公益服务的表达 一、词义解释 “Pro bono” 是一个源自拉丁语的短语,完整表达为 “pro bono publico”,意思是“为了公众利益”(for the public good)。在现代英语中,它…...
16. C语言 字符串详解
本章目录: 前言C 字符串的基础概念字符串的定义字符串的内存表示 常见的字符串操作函数示例代码 深入探讨字符串长度计算strlen 与 sizeof 的区别 字符串操作的注意事项**1. 字符数组的大小**2. 字符数组和字符指针的区别3. 使用安全函数 字符串的遍历与格式化输出**遍历字符串…...
使用Buildroot开始嵌入式Linux系统之旅-3
文章目录 at91bootstrap操作教程修改at91bootstrap具体配置重新编译at91bootstrap U-Boot操作教程修改U-Boot具体配置重新编译U-Boot Linux Kernel操作教程修改Linux Kernel具体配置重新编译Linux Kernel buildroot操作进阶生成图形化软件模块依赖关系查看具体软件模块依赖关系…...
[免费]SpringBoot+Vue新能源汽车充电桩管理系统【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的SpringBootVue新能源汽车充电桩管理系统,分享下哈。 项目视频演示 【免费】SpringBootVue新能源汽车充电桩管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息化时代的到来࿰…...
【已解决】【记录】2AI大模型web UI使用tips 本地
docker desktop使用 互动 如果需要发送网页链接,就在链接上加上【#】号 如果要上传文件就点击这个➕号 中文回复 命令它只用中文回复,在右上角打开【对话高级设置】 输入提示词(提示词使用英文会更好) Must reply to the us…...
44.ComboBox的数据绑定 C#例子 WPF例子
固定最简步骤,包括 XAML: 题头里引入命名空间 标题下面引入类 combobox绑定资源属性和选择属性,block则绑定和combobox一样的选择属性 C#: 通知的类,及对应固定的任务 引入字段 引入属性 其中资源是只读的 选…...
物联网之传感器技术
引言 在数字化浪潮席卷全球的今天,物联网(IoT)已成为推动各行各业变革的重要力量。而物联网传感器,作为物联网感知层的核心技术,更是扮演着不可或缺的角色。它们如同人类的五官,能够感知物理世界中的各种信…...
QTreeWidget QTreeWidgetItem
QTreeWidgetItem 是 Qt 框架中用于在 QTreeWidget 中表示树形结构中每个节点的类。它是 QTreeWidget 的一部分,允许您创建和管理层次结构的数据展示。 QTreeWidgetItem 用于表示树形结构中的单个节点。 添加子节点: 可以通过 addChild() 方法向节点添加…...
torch.einsum计算张量的外积
torch.einsum 是一种强大的张量操作工具,可以通过爱因斯坦求和约定(Einstein summation convention)来简洁地表示复杂的张量运算。通过它,我们可以高效地计算矩阵乘法、转置、点积、外积等操作。 以下是关于如何使用 torch.einsum 计算两个四维张量在第三维度上的外积的解…...
PostgreSQL 超级管理员详解
1. 什么是 PostgreSQL 超级管理员 PostgreSQL 超级管理员(superuser)是拥有数据库系统最高权限的用户。他们可以执行任何数据库操作,包括但不限于创建和删除数据库、用户、表空间、模式等。超级管理员权限是 PostgreSQL 中权限的最高级别。 …...
RabbitMQ 工作模式使用案例之(发布订阅模式、路由模式、通配符模式)
Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 🌱🌱个人主页:奋斗的明志 🌱🌱所属专栏:RabbitMQ 📚本系列文章为个人学…...
【2024年华为OD机试】(C卷,100分)- 机场航班调度程序 (Java JS PythonC/C++)
一、问题描述 题目描述 XX市机场停放了多架飞机,每架飞机都有自己的航班号,如CA3385,CZ6678,SC6508等,航班号的前2个大写字母(或数字)代表航空公司的缩写,后面4个数字代表航班信息…...
Vue.js组件开发-使用地图绘制轨迹
在Vue.js中开发一个组件来展示地图并绘制轨迹,可以使用诸如Leaflet.js、Mapbox GL JS或百度地图等地图库。这些库提供了丰富的API来创建和定制地图,以及绘制路径、标记和其他地图元素。 示例: 1. 安装Leaflet.js 首先,需要安装…...
vue 与 vue-json-viewer 实现 JSON 数据可视化
前言 接口的调试和测试是确保系统稳定性的重要步骤。为了让开发人员和测试人员能够直观地查看接口返回的 JSON 数据,使用合适的工具至关重要。vue-json-viewer 插件为 vue 开发者提供了一个简单而强大的解决方案。本文将详细介绍如何在 vue 项目中使用该插件&#x…...
ubuntu Android : adb logcat 过滤多个log
指定字符串的log,可以用下面的形式,注意加-E和单引号: adb shell " logcat | grep -E strings1|strings2 " 参考:Android : adb logcat 过滤多个log 用adb shell “ logcat | grep -E ‘strings1| strings2 ‘ “ 形…...
kubeneters-循序渐进Cilium网络(三)
文章目录 概要命名空间之间的路由同一节点上的 Pod 到 Pod 路由跨节点的 Pod 间路由总结 概要 在前一篇讨论网络接口的内容中,详细分析了如何识别所有参与 Pod 间路由的接口。同时,以简明的非技术语言阐述了 Cilium 在 Kubernetes 集群中的路由机制。接…...
SPPF中的CSP结构解析
在YOLOv5/v8等目标检测模型中,SPPF 内的 CSP 结构特指 SPPFCSPC 模块或类似变体。它是一种将空间金字塔池化层(SPPF) 与跨阶段部分网络思想(CSPNet) 紧密结合的复合模块,旨在更高效地进行多尺度特征融合并提…...
OpenClaw+千问3.5-9B自动化测试:自然语言描述生成单元测试用例
OpenClaw千问3.5-9B自动化测试:自然语言描述生成单元测试用例 1. 为什么需要自然语言生成测试用例 作为一名长期奋战在代码一线的开发者,我深知单元测试的重要性,但编写测试用例往往比实现功能本身更耗时。特别是在快速迭代的项目中&#x…...
AI大模型学习路线图:小白程序员必看,收藏这份高薪入局指南!
AI大模型学习路线图:小白程序员必看,收藏这份高薪入局指南! 本文提供了一套完整的AI大模型学习路线,涵盖大模型基础认知、核心技术(RAG、Prompt、Agent)、开发基础能力、应用场景落地、项目实操流程及面试求…...
2026年4月3日 理论基石:数据量与模型参数量的关系
文章目录1. 理论基石:数据量与模型参数量的关系Kaplan Scaling Laws (OpenAI, 2020)Chinchilla Scaling Laws (DeepMind, 2022)2. 实战计算:针对你的 nanoGPT 实验第一步:估算总 Token 数第二步:计算训练步数 (max_iters)第三步&a…...
DAY3--SQL单字段去重查询
SQL基础入门:电商用户数据单字段去重查询实操 这一章能解决什么电商工作问题? 前两章我们学了SELECT *(全量看数据)和SELECT 字段列表(精准取字段)。这一章讲的是另一个高频操作:去重。 我讲一个…...
AI深度学习中的自动微分与梯度下降机制解析
AI深度学习中的自动微分与梯度下降机制解析...
三态模型:**就绪**(已获除CPU外所有资源,等待调度)、**运行**(正在CPU执行)、**阻塞**(等待某事件如I/O完成,主动放弃CPU)
🔹 进程与线程 进程是资源分配的基本单位,拥有独立地址空间;线程是CPU调度的基本单位,同一进程内线程共享代码段、数据段和打开文件等资源,但有独立栈和寄存器上下文。线程切换开销远小于进程切换(无需TLB刷…...
实验室服务器远程访问终极方案:SSH 反向隧道 + systemd 自动重连
🚀 实验室服务器远程访问终极方案:SSH 反向隧道 systemd 自动重连适用于: 没有公网 IP 的实验室服务器想用 VSCode / SSH / Jupyter 远程开发希望稳定、自动重连、开机自启🧠 一、问题背景 在很多实验室环境中: GPU 服…...
如何用xianyu_spider实现高效电商数据采集?从入门到精通的完整指南
如何用xianyu_spider实现高效电商数据采集?从入门到精通的完整指南 【免费下载链接】xianyu_spider 闲鱼APP数据爬虫 项目地址: https://gitcode.com/gh_mirrors/xia/xianyu_spider 在当今电商竞争日益激烈的环境下,获取准确、及时的市场数据成为…...
专题:哈希结构(已完结)
1.有效的字母异位词 class Solution { public:bool isAnagram(string s, string t) {unordered_map<char,int> mymap;for(auto c:s){mymap[c]mymap[c]1;}for(auto c:t){mymap[c]mymap[c]-1;}for(auto item:mymap){if(item.second!0){return false;}}return true;} };2.两…...
