
学习目标在工作中用到信号量记录一下一、概念Semaphore 一般译作信号量它也是一种线程同步工具主要用于多个线程对共享资源进行并行操作的一种工具类。它代表了一种许可的概念是否允许多线程对同一资源进行操作的许可使用 Semaphore 可以控制并发访问资源的线程个数。注意本片引入一个比喻信号量就是你要去一个房间但是有一个门卫在房间门口检查二、基础使用2.1初始化 public Semaphore(int initialCount, int maximumCount);参数 1initialCount 初始可用资源数参数initialCount是设置默认最多可以有几个访问也是设置初始有多少比如你设置2那就是最开始就有2个资源可以用可以去访问不用等释放但是最多也是只有同时2个访问也就是一开始门卫就允许2个人进去而且也规定了门卫一次只允许2个人进去房间参数 2maximumCount 最大资源上限含义信号量计数器能达到的最大值封顶值硬性规则 每次调用Release(n)会把计数器 n 如果相加后 新计数 maximumCount → 直接抛出SemaphoreFullException报错。作用限流保护防止无限释放资源导致并发失控比如你设置了5信号量计数器能达到的最大值最多就是只能是5也就是门卫只允许最多同时有5个人在房间附近而且包括了在房间里的你得从房间走了1个才能再来一个2.2 阻塞等待允许访问的信号量 s.WaitOne()WaitOne()其实是做减法一条指令就是减一就相当于门卫一次只允许同时两个人进去进去一个人就少一个名额名额减少到了0那就要排队等2.3 s.Release(int x) 释放资源这个相当于叫人来排队但是要注意门卫的可接受最多人数比如设置了37已经有3个人在访问了在这三个人干完活之后这时候只能最多再叫3个人来排队理论上来说就是s.WaitOne()多少就s.Release()多少三、使用场景信号量有两种使用场景一种是并发限流也就是控制多少个线程可以访问一个方法还有是生产者消费者任务通知3.1 并发限流多线程抢固定名额WaitOne 和 Release 必须成对基础格式如下WaitOne()占用 1 个名额计数器 -1执行需要限流的耗时逻辑Release(1)归还名额计数器 1然后多个线程一起执行这个方法但是因为规定了最多是5所以虽然创建了一百个但是制最多只能有五个线程执行之后要等一个线程执行完了才到下一个Semaphore s new Semaphore(5,5); void TaskWork() { s.WaitOne(); // 抢名额 try { // 并发受限的业务代码 Thread.Sleep(2000); } finally { s.Release(1); // 用完必须归还 } } ///////////////////// int p 0; Thread x; for(int i0;i100;i) { x new Thread(TaskWork); x.Start(); }3.2 生产者消费者任务通知生产者放任务 Release消费者取任务 WaitOne消费者不 Release生产者addTaskThread / 界面按钮往队列加任务 →Release(n)计数器 n消费者唯一通信线程WaitOne()计数器 -n取出任务执行消费者执行完任务不归还资源关键特征不对称生产者 Release消费者只 Wait 不 Release全程只有1 个消费线程不存在并发控制initialCount 固定 0启动无任务直接阻塞maximumCount 是任务堆积上限不是线程上限。// 生产者新增任务 lock(lockObj) { queue.Enqueue(task); } _TaskSemaphore.Release(1); // 消费者单一线程循环 Task.Run{ while(true) { _TaskSemaphore.WaitOne(); lock(lockObj) { var task queue.Dequeue(); } // 执行Modbus通信没有Release } }3.3 特殊的一种一个按钮就是干活但是点了超过5次就不会输入ok只有点击另外一个按钮Release一个才会继续输出okSemaphore s new Semaphore(5,5); private void button4_Click(object sender, EventArgs e) { Task.Run(() { s.WaitOne(); Console.WriteLine(ok); } ); } private void button5_Click(object sender, EventArgs e) { s.Release(1); }学习时间26.07.13