C# dotnet 的锁 SemaphoreSlim 和队列
本文主要是试验在顺序进入等待 SemaphoreSlim 的任务是否会按照顺序经过锁执行
我在一个有趣的WPF程序里面,需要限制任务同时执行的线程数量,不然用户就会说用我的程序会让电脑卡渣。而我的任务是需要按照指定顺序执行的,我需要每次同时仅执行10个任务,同时任务执行按照传入的顺序
此时可以用到 SemaphoreSlim 这个类,这个类的作用如下,给定初始的可以通过锁的数量,以及这个最大可以通过锁的数量。通过 Wait 方法进行等待,如果当前已经有超过可以通过的任务通过了,那么在 Wait 方法将会阻塞。如果没有超过可以通过的数量,那么将可以通过
使用 Release 方法可以添加一个或多个可以通过的数量,但是可以通过的数量最大不会超过初始化时传入的最大可以通过锁的数量的值
如下面代码
var semaphoreSlim = new SemaphoreSlim(10, 20);
此时表示初始化的时候,可以让 10 个任务通过锁,也就是初始化的时候可以有10次调用 Wait 方法能通过
而第二个参数表示最大的可以通过的数量,通过 Release 可以添加一个或多个可以通过锁的任务,如 semaphoreSlim.Release(100); 表示设置有 100 个可以通过锁的任务,但是实际上在上面代码里面,因为设置了最大值是 20 也就是即使写 100 其实之后能通过的任务只有 20 个
而本文的测试在于我有任务按照顺序调用 Wait 方法进入等待,如我的任务有序号,我按照任务1 任务2 任务3 的顺序调用Wait方法,同时此时的锁的可以通过的数量是 0 也就是所有任务在等待
之后我通过 Release 方法的不断调用,请问此时通过锁的任务是否和队列一样,先等待的任务就先通过锁。答案是这样的
先调用 Wait 方法的任务,在锁开始释放的时候就先通过,我通过一个有趣的代码用来测试
我需要有很多线程进入锁的 Wait 方法,但是这些线程每个线程是一个任务,这些任务有顺序,进入等待方法的时候按照顺序进入
而小伙伴都知道,创建线程的先后顺序不会等于线程执行的先后顺序,所以我使用了 AutoResetEvent 在线程创建然后执行开始之后再创建下一个线程
先通过 SemaphoreSlim 创建一个初始值是 10 而最大值是 10 的锁,然后创建一个 AutoResetEvent 设置默认能通过一次
var semaphoreSlim = new SemaphoreSlim(10, 10);
private static readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(true);
接下来进入循环创建线程,创建线程的时候先等待 AutoResetEvent 锁,而在线程执行的时候释放 AutoResetEvent 锁,这样就能让线程一定是在上一个线程执行之后再创建。而设置 AutoResetEvent 的初始值是通过,也就是第一个线程可以创建,但第二个线程需要等待第一个线程开始执行再创建
for (int i = 0; i < 1000; i++)
{
var n = i;
_autoResetEvent.WaitOne();
new Thread(() => { GeregelkunoNeawhikarcee(semaphoreSlim, n); }).Start();
}
添加 GeregelkunoNeawhikarcee 方法,在方法进入的时候,也就是线程开始执行,释放 AutoResetEvent 锁,这样就能让下一个线程创建
_autoResetEvent.Set();
进入等待 SemaphoreSlim 此时等待是按照线程创建的顺序等待
semaphoreSlim.Wait();
接下来输出当前的任务号,主要用来调试是否通过锁的顺序和线程进入等待的顺序相同
Console.WriteLine(n);
接下来通过 Thread.Sleep 模拟执行长任务
在任务执行完成之后释放锁让下一个任务开始,全部代码放在这里
static void Main(string[] args)
{
var semaphoreSlim = new SemaphoreSlim(10, 10);
for (int i = 0; i < 1000; i++)
{
var n = i;
_autoResetEvent.WaitOne();
new Thread(() => { GeregelkunoNeawhikarcee(semaphoreSlim, n); }).Start();
}
Console.Read();
}
private static readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(true);
private static void GeregelkunoNeawhikarcee(SemaphoreSlim semaphoreSlim, int n)
{
Console.WriteLine($"{n} 进入");
_autoResetEvent.Set();
semaphoreSlim.Wait();
Console.WriteLine(n);
Thread.Sleep(TimeSpan.FromSeconds(1));
semaphoreSlim.Release();
}
可以看到代码是按照顺序输出的
本文代码放在github欢迎小伙伴访问

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
C# dotnet 的锁 SemaphoreSlim 和队列的更多相关文章
- 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操
昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...
- redis分布式锁和消息队列
最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP ...
- python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式
(1)锁:进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 虽然使用加锁的形式实现了 ...
- 互斥锁,IPC队列
进程同步(锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,part1:共享同一打印终端,发现会有多行内容打印到一行的现象(多个进程共享并抢占同一个 ...
- 4-[多进程]-互斥锁、Queue队列、生产者消费者
1.互斥锁 (1)为什么需要互斥锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如下 #并发运行,效率 ...
- python 锁 信号量 事件 队列
什么是python 进程锁? #同步效率低,但是保证了数据安全 重点 很多时候,我们需要在多个进程中同时写一个文件,如果不加锁机制,就会导致写文件错乱 这个时候,我们可以使用multiprocess ...
- Zookeeper--分布式锁和消息队列
在java并发包中提供了若干锁的实现,它们是用于单个java虚拟机进程中的:而分布式锁能够在一组进程之间提供互斥机制,保证在任何时刻只有一个进程可以持有锁. 分布式环境中多个进程的锁则可以使用Zook ...
- 进击的Python【第九章】:paramiko模块、线程与进程、各种线程锁、queue队列、生产者消费者模型
一.paramiko模块 他是什么东西? paramiko模块是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 先来个实例: import param ...
- GIL全局解释器锁、死锁、递归锁、线程队列
目录 GIL全局解释锁 多线程的作用 测试计算密集型 IO密集型 死锁现象 递归锁 信号量(了解) 线程队列 GIL全局解释锁 GIL本质上是一个互斥锁. GIL是为了阻止同一个进程内多个进程同时执行 ...
- java-spring基于redis单机版(redisTemplate)实现的分布式锁+redis消息队列,可用于秒杀,定时器,高并发,抢购
此教程不涉及整合spring整合redis,可另行查阅资料教程. 代码: RedisLock package com.cashloan.analytics.utils; import org.slf4 ...
随机推荐
- C# OpenCvSharp-HoughCircles(霍夫圆检测) 简单计数
效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.D ...
- Oracle regexp_replace 手机号脱敏
select '18012345678',regexp_replace('18012345678','(.){4}','****',4,1) from dual;
- verilog基本语法之always和assign
always和assign的作用 一.语法定义 assign,连续赋值.always,敏感赋值.连续赋值,就是无条件全等.敏感赋值,就是有条件相等.assign的对象是wire,always的对象是r ...
- Linux C++ 连接 MySQL
安装MySQL 可以参考这篇文章<在Ubuntu上安装MySQL> 连接 具体可以看官方的MySQL参考手册 示例代码 #include<iostream> #include& ...
- 使用OHOS SDK构建bullet
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/bulletphysic ...
- 体验Semantic Kernel图片内容识别
前言 前几日在浏览devblogs.microsoft.com的时候,看到了一篇名为Image to Text with Semantic Kernel and HuggingFace的文章.这篇文章 ...
- Java HashMap 和 HashSet 的高效使用技巧
Java HashMap HashMap 是一种哈希表,它存储键值对.键用于查找值,就像数组中的索引一样.HashMap 的优势在于它可以使用任何类型作为键,并且查找速度很快. 创建 HashMap ...
- 全面指南:技术写作与编辑工具 Markdown、Git 研究工具
技术写作工具 在技术写作领域,"工具"是指技术写作者用于创建.管理和发布高质量技术文档的各种软件和应用程序.这包括文字处理器.桌面出版应用程序.XML 编辑器.内容管理系统等等.一 ...
- RabbitMQ 04 直连模式-Java操作
使用Java原生的方式使用RabbitMQ现在已经较少,但这是基础,还是有必要了解的. 引入依赖. <dependency> <groupId>com.rabbitmq< ...
- climits 与 符号常量
climits 在老式中是 limits.h 一.引入 #include <climits> 或者 #include <limits.h> 二.符号常量 符号常量 表示 CH ...