【C#】并行编程实战:同步原语(2)

news2024/12/24 8:00:59

         在第4章中讨论了并行编程的潜在问题,其中之一就是同步开销。当将工作分解为多个工作项并由任务处理时,就需要同步每个线程的结果。线程局部存储和分区局部存储,某种程度上可以解决同步问题。但是,当数据共享时,就需要用到同步原语。

        因篇幅所限,本章为第2篇。主要介绍锁、互斥锁和信号灯。

        本教程对应学习工程:魔术师Dix / HandsOnParallelProgramming · GitCode


5、锁、互斥锁和信号灯

        锁(Lock)和互斥锁(Mutex)是仅允许一个线程访问受保护资源的锁结构。信号灯(Semaphore)也是一种锁结构,它允许指定数量的线程访问受保护的资源。

同步原语

分配的线程数

跨进程

锁(Lock)

1

×

互斥锁(Mutex)

1

信号灯(Semaphore)

轻量信号灯(SemaphoreSlim)

×

        由于锁会限制其他线程访问共享资源,所以一定不要锁住会造成阻塞的代码,否则性能会大幅下降。一般来讲,锁只用于关键节

关键节(Critical Section):

        线程执行路径的一部分,必须对其进行保护以防止并发访问,进而维护某些不变性(Invariant)。关键节本身不是同步原语,但是它依赖于同步原语。

5.1、锁

        在之前的代码,我们做一下改造:

        private static object lockObj = new object();
        public static void RunTestAddFunctionWithLock()
        {
            TestValueA = 0;
            TestValueB = 0;
            m_IsFinishOnce = false;

            Task.Run(() =>
            {
                Parallel.For(0, 10000, x =>
                {
                    lock (lockObj)
                    {
                        TestValueA = x;
                        TestValueB = x;
                        m_IsFinishOnce = TestValueA >= TestValueB;
                    }
                });
                Debug.Log("运行完成");
            });

        这个其实是非常常见的锁用法了,如上示例代码,就永远不会出现异常值的情况 m_IsFinishOnce 的值永远为 true。与 Lock 语句类似,还有一种类似写法:

Monitor.Enter(lockObj);
TestValueA = x;
TestValueB = x;
m_IsFinishOnce = TestValueA >= TestValueB;
Monitor.Exit(lockObj);

Monitor 类 (System.Threading) | Microsoft Learn提供同步访问对象的机制。 icon-default.png?t=N658https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.monitor?view=netstandard-2.1        简单来说,Lock 是 Monitor 的快捷方式,Lock 能实现的 Monitor 也都能实现。想要详细了解这两者可以扩展阅读以下连接:

Lock VS Monitor - 知乎介绍 介绍 对开发人员来说,处理关键代码部分的多线程应用程序是非常重要的。 Monitor和lock是c#语言中多线程应用程序中提供线程安全的方法(lock关键字的本质就是对Monitor的封装)。两者都提供了一种机制来确保只…https://zhuanlan.zhihu.com/p/553789674

5.2、互斥锁

        Lock 或 Mutex 只能锁定单进程,毕竟我们锁定的类只是在单进程创建的。如果出现多个进程竞争同一个资源(例如都在对同一个文档进行写入),就会报错。此时我们需要 Mutex ,创建内核级别的应用锁。

Mutex 类 (System.Threading) | Microsoft Learn还可用于进程间同步的同步基元。 icon-default.png?t=N658https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.mutex?view=netstandard-2.1        用法也很简单;

private static Mutex mutex = new Mutex(false, "TestMutex");
……
mutex.WaitOne();
TestValueA = x;
TestValueB = x;
m_IsFinishOnce = TestValueA >= TestValueB;
mutex.ReleaseMutex();

        不过我感觉,在一般的游戏开发都是单进程的逻辑,很少会需要用到互斥锁。可能在工程流水线开发的过程中,用到这个的情况多一些。

        Lock 和 Mutex 只能从获得它们的线程释放。

5.3、信号灯

        (书上称之为信号量,但微软文档上称之为信号灯,这里采用微软的说法,以下通称为信号灯)

        Lock、Monitor、Mutex 仅允许一个线程访问受保护的资源。但是有时我们也需要多个进行能够访问共享资源。例如资源池(Resource Pooling)和节流(Throttling)的应用场景都需要让多个线程能同时访问到共享资源。

        与 Lock 或 Mutex 不同,信号灯(Semaphore)是线程不可知的,这意味着任何线程都可以调用 Semaphore 的释放。信号灯也可以跨进程工作。

Semaphore 类 (System.Threading) | Microsoft Learn限制可同时访问某一资源或资源池的线程数。 icon-default.png?t=N658https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.semaphore?view=netstandard-2.1        示例代码如下:

        private static Semaphore semaphore = new Semaphore(1, 3);//初始资源量,资源总量
        public static void RunWithSemaphore()
        {
            Task.Run(() =>
            {
                Parallel.For(0, 10, async x =>
                {
                    Debug.Log($"【{x} 】进入运行!");
                    semaphore.WaitOne();
                    await Task.Delay(1000);
                    semaphore.Release();
                    Debug.LogError($"【{x}】 完成运行!");
                });
                Debug.Log("全部运行完成");
            });
        }

        Semaphore 传入的2个参数,一个是初始资源量,一个是资源总量。像如上的代码,其实就是一个等一个,每隔 1s 执行完成一个任务:

         如果将 initialCount 设置为 2 ,这就是一次执行两个任务。这个原理其实就是 PV操作 的意思,通过信号灯来动态控制线程的阻塞与执行。

全局信号灯(Global Semaphore):

        对于操作系统是全局的,应用了内核级别的锁原语。使用名称创建(创建时进行了命名)的任何信号灯都将创建为全局信号灯,否则则为局部信号灯。


(未完待续)

 本教程对应学习工程:魔术师Dix / HandsOnParallelProgramming · GitCode

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

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

相关文章

电商项目“商品分类浏览”如何测试?附详细思维导图

电商项目无论是工作中,还是面试中,都是一个高频出现的词。面试官非常热衷提问关于电商项目的问题。例如商品分类怎么测试?购物车怎么测试?订单怎么测试?优惠券怎么测试?支付怎么测试?等等 今天…

【Spring Cloud系列】- Ribbon详解与实战

【Spring Cloud系列】- Ribbon详解与实战 文章目录 【Spring Cloud系列】- Ribbon详解与实战一、什么是Ribbon二、Spring Cloud中Ribbon应用Ribbon使用步骤如下 三、Ribbon负载均衡策略设置3.1 全局策略设置3.2 基于注解的针对单个服务的 Ribbon 负载均衡策略3.2.1 注解方式3.2…

『赠书活动 | 第十五期』《Java核心技术·卷II》

💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! 『赠书活动 | 第十五期』 本期书籍:《Java核心技术卷II》 公众号赠书:第六期 参与方式:关注公众号:低调而…

折叠屏手机的屏幕,华为Mate X3给出了一份“内外兼修”的解决方案

说起折叠屏手机,屏幕一直都是这个领域的重头戏,很多人都对折叠屏手机有一种刻板印象,那就是脆弱。但是,3月份华为最新推出的Mate X3可以说是非常的亮眼,在内外屏幕、水滴铰链、影像系统等多个核心部件的全方位提升&…

MKPFMSEG字段增强后 关于 BAPI_GOODSMVT_CREATE 的extensionin的增强参数带入。

首先在MKPF 的增强表结构 BAPI_TE_XMKPF 增强字段 如果是行项目上的 BAPI_TE_XMSEG 然后在实际赋值的时候 前面14位数是 10位物料凭证号 4位 年度 CLEAR: ls_extensionin.ls_extensionin-STRUCTURE BAPI_TE_XMKPF.ls_extensionin-valuepart114(50) ls_…

告诉你有哪些音频转换成mp3免费软件

曾经有一个名叫小华的音乐爱好者,他对于收集和欣赏各种类型的音频文件情有独钟。然而,他在构建自己的音乐库时遇到了一个困扰:不同设备和平台支持的音频格式千差万别,这让他无法顺利地播放和分享自己喜爱的音乐。幸运的是&#xf…

GTK列表显示文本和图片

使用GtkTreeView控件显示包含文本和图片的列表,GtkTreeView/GtkListStore或者GtkTreeView/GtkTreeModel使用的是MVC设计理念。 关于MVC: M层: model 数据模型层(处理数据的增删改查) 提供数据 V层: Views 视图层 (数据展示) 渲染数据 C层: controller 控制层(处理业…

【UI框架-uView】Input输入框如何使用前后槽?

【UI框架-uView】Input输入框如何使用前后槽? 官方链接如下:Input输入框 - 前后槽 前槽如下: 后槽如下: 可以看到,前后槽的灵活使用,不仅方便我们的布局,还可以在input中实现复杂的应用。 注意…

Vue 组件化开发

文章目录 前言组件化开发父子组件相互传数据父传子:自定义属性子传父:自定义事件父子组件互传案例 插槽 slot多个插槽 总结组件化开发总结Vue组件的基本组成子组件使用的三个步骤父子组件相互传递数据 前言 提示:这里可以添加本文要记录的大…

jenkins 创建项目的ci

一.创建视图 1.点击加号 选择列表视图 2.输入名称,点击确定 二.创建任务 1.点击到你新建的视图之后,再点击文本中的创建一个新的任务。 2.进入创建页面后首先填写描述 三.选择丢弃旧的构建 保持构建的天数是指:是指保留多少天内的构建 …

【基于FPGA的芯片设计】RISC-V的20条指令CPU设计

实验板卡:xc7a100tlc sg324-2L,共20个开关 实验要求:

【C#】并行编程实战:同步原语(1)

在第4章中讨论了并行编程的潜在问题,其中之一就是同步开销。当将工作分解为多个工作项并由任务处理时,就需要同步每个线程的结果。线程局部存储和分区局部存储,某种程度上可以解决同步问题。但是,当数据共享时,就需要用…

Chrome内建DNS导致的解析错误修复

Index Chrome内建DNSDisable Async DNS resolver Chrome内建DNS 实际上 , Chrome在使用自己的DNS来进行域名的解析 , 这导致有时候一些域名解析会出现错误 , 导致访问速度变慢 , 例如 blog.csdn.net 使用谷歌的 8.8.8.8 dns解析就会 , 解析到香港的ip上去 , 导致访问速度变慢 …

群晖NAS:docker查询注册表失败解决方案 docker安装网心云、mysql等

群晖NAS:docker查询注册表失败解决方案 差不多2023年4月底开始的,docker内不能直接搜索注册表。据说是有人在库里放了一些有意思的东西,被和谐掉了,所以也别指望什么时候能解封。 网上很多案例,都不能用。还有奇葩的…

史上最细接口测试详解,接口测试从0到1实施,一篇打通...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、接口测试描述定…

【C语言】-- 死循环了怎么办?

#include <stdio.h> int main() {int i 0;int arr[] {1,2,3,4,5,6,7,8,9,10};for(i0; i<12; i){arr[i] 0;printf("hello\n");}return 0; } 阅读上面这个代码&#xff0c;我们会认为这不就是简单的数组访问越界么。那么这段代码就应该会报错&#xff0c;…

macOS Sonoma 14beta 3 (23A5286i)第二个更新「附黑/白苹果镜像下载」

系统镜像下载&#xff1a; 系统介绍 黑果魏叔 7 月12 日消息&#xff0c;苹果今天发布 macOS Sonoma 14.0 Beta 3&#xff08;内部版本号&#xff1a;23A5286i&#xff09;第二个更新。 目前尚不清楚苹果为什么要发布 macOS Sonoma Beta 3 的第二个版本&#xff0c;但它可能…

外包干了2年,我裸辞了...

我25岁&#xff0c;中级测试&#xff0c;外包&#xff0c;薪资13.5k&#xff0c;人在上海。内卷什么的就不说了&#xff0c;而且人在外包那些高级精英年薪大几十的咱也接触不到&#xff0c;就说说外包吧。 假设以我为界限&#xff0c;25岁一线城市13.5k&#xff0c;那22-24大部…

CUDA11.1、cuDNN8.6.0、Tensorrt8.5.3,ubuntu20.04安装过程记录

CUD11.1 下载地址&#xff1a;CUDA Toolkit Archive | NVIDIA Developer 安装&#xff1a; wget https://developer.download.nvidia.com/compute/cuda/11.1.1/local_installers/cuda_11.1.1_455.32.00_linux.run sudo sh cuda_11.1.1_455.32.00_linux.run 对于不是sudo用户&…

CRYPTO-36D-飞鸽传书

0x00 前言 CTF 加解密合集&#xff1a;CTF 加解密合集 0x01 题目 TVdJd09HRm1NamMyWkdKak56VTVNekkzTVdZMFpXVTJNVFl5T0Rrek1qUWxNRUZsTW1GbE0yRXlNelV3TnpRell6VXhObU5rWVRReE1qUTVPV0poTTJKbE9TVXdRV0prWlRVeVkySXpNV1JsTXpObE5EWXlORFZsTURWbVltUmlaRFptWWpJMEpUQkJaVEl6…