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 ...
随机推荐
- 面试官:Kafka和ES选主有什么区别?
Kafka 和 ES 都是用来处理大数据的中间件,一个是消息中间件的代表(Kafka),另一个是大数据搜索引擎的代表(ES).它们在 Java 领域的使用非常广泛,在大数据方面就更不用说了,但它们的选 ...
- vector的Erase相关
vector<int>Vect; Vect.insert(Vect.begin()+2, 50); for (auto it=Vect.begin();it!=Vect.end();++i ...
- 记录--JS精粹,原型链继承和构造函数继承的 “毛病”
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 先从面向对象讲起,本瓜认为:面向对象编程,它的最大能力就是:复用! 咱常说,面向对象三大特点,封装.继承.多态. 这三个特点,以" ...
- KingbaseES V8R6集群运维案例之---sys_monitor.sh start启动动态库错误
案例说明: 在KingbaseES V8R6集群部署了postgis后,执行sys_monitor.sh start启动集群时,出现动态库错误,如下图所示: 适用版本: KingbaseES V8R6 ...
- Ant Design Vue Tree 选中子节点同时半选中父级节点
需要实现的效果: 1.子菜单如果不是全部选中,一级菜单半选. 2.子菜单全选,一级菜单选中. 3.一级菜单选择,二级菜单全选. 4.没有二级菜单,则只控制一级菜单. 主要用到的属性是checked和h ...
- Android弹出UI界面---Toast
1.默认展示 1 // 第一个参数:当前的上下文环境.可用getApplicationContext()或this 2 // 第二个参数:要显示的字符串.也可是R.string中字符串ID 3 // ...
- Git入门指南:从新手到高手的完全指南
Git是一种强大的分布式版本控制系统,广泛应用于软件开发中.它的使用不仅可以帮助开发团队更好地管理代码,还可以提高团队协作效率和代码质量.随着软件开发的不断发展,版本控制成为了程序员必备的一项技能.G ...
- 10. Conclusion
10.1 Matrix Factorizations A = LU = (Lower triangular L with 1's on the diagonal)(Upper triangular U ...
- MogDB/openGauss数据库package关键字的两种用法
MogDB/openGauss 数据库 package 关键字的两种用法 本文出处:https://www.modb.pro/db/237701 package 关键字在 MogDB 数据库里有两种用 ...
- openGauss资源池化开发者入门指南(一)
openGauss资源池化开发者入门指南(一) 一.内容简介 openGauss 资源池化是 openGauss 推出的一种新型的集群架构.通过 DMS 和 DSS 组件,实现集群中多个节点的底层存储 ...