c#之信号量Semaphore

学习目标:

在工作中用到信号量,记录一下


一、概念

Semaphore 一般译作 信号量,它也是一种线程同步工具,主要用于多个线程对共享资源进行并行操作的一种工具类。它代表了一种许可的概念,是否允许多线程对同一资源进行操作的许可,使用 Semaphore 可以控制并发访问资源的线程个数。

注意本片引入一个比喻;信号量就是你要去一个房间但是有一个门卫在房间门口检查;

二、基础使用

2.1初始化 public Semaphore(int initialCount, int maximumCount);

参数 1:initialCount 初始可用资源数

参数initialCount是设置默认最多可以有几个访问,也是设置初始有多少;比如你设置2,那就是最开始就有2个资源可以用可以去访问,不用等释放;但是最多也是只有同时2个访问;也就是一开始门卫就允许2个人进去,而且也规定了门卫一次只允许2个人进去房间,

参数 2:maximumCount 最大资源上限

  1. 含义:信号量计数器能达到的最大值,封顶值
  2. 硬性规则: 每次调用 Release(n) 会把计数器 +n; 如果相加后 新计数 > maximumCount → 直接抛出 SemaphoreFullException 报错。
  3. 作用:限流保护,防止无限释放资源导致并发失控

比如你设置了5,信号量计数器能达到的最大值最多就是只能是5;也就是门卫只允许最多同时有5个人在房间附近而且包括了在房间里的;你得从房间走了1个才能再来一个;

2.2 阻塞,等待允许访问的信号量 s.WaitOne()

WaitOne()其实是做减法;一条指令就是减一;就相当于门卫一次只允许同时两个人进去,进去一个人就少一个名额;名额减少到了0那就要排队等;

2.3 s.Release(int x) 释放资源

这个相当于叫人来排队;但是要注意门卫的可接受最多人数;比如设置了(3,7),已经有3个人在访问了,在这三个人干完活之后,这时候只能最多再叫3个人来排队,理论上来说就是s.WaitOne()多少就s.Release()多少

三、使用场景

信号量有两种使用场景,一种是并发限流也就是控制多少个线程可以访问一个方法;还有是生产者消费者任务通知;

3.1 并发限流

多线程抢固定名额,WaitOne 和 Release 必须成对,基础格式如下:

  1. WaitOne():占用 1 个名额,计数器 -1
  2. 执行需要限流的耗时逻辑
  3. Release(1):归还名额,计数器 +1

然后多个线程一起执行这个方法,但是因为规定了最多是5,所以虽然创建了一百个但是制最多只能有五个线程执行,之后要等一个线程执行完了才到下一个;

cs 复制代码
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 i=0;i<100;i++)
            {
                x = new Thread(TaskWork);
                x.Start();
               
            }

3.2 生产者消费者任务通知

生产者放任务 Release,消费者取任务 WaitOne,消费者不 Release

  1. 生产者(addTaskThread / 界面按钮):往队列加任务 → Release(n),计数器 +n
  2. 消费者(唯一通信线程):WaitOne() 计数器 -n,取出任务执行
  3. 消费者执行完任务不归还资源

关键特征

  1. 不对称:生产者 Release,消费者只 Wait 不 Release;
  2. 全程只有1 个消费线程,不存在并发控制;
  3. initialCount 固定 0,启动无任务直接阻塞;
  4. maximumCount 是任务堆积上限,不是线程上限。
cs 复制代码
// 生产者:新增任务
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一个才会继续输出ok;

cs 复制代码
Semaphore 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


相关推荐
lll23526917798 小时前
2026行业语音转写工具专业术语转写功能横向分析
笔记·智能手机
解决小子17 小时前
【虚幻引擎】【C++】【GAS框架】构建角色基类、属性集、数值钳制
c++·笔记·游戏引擎·虚幻·gas·能力系统
破芽18 小时前
learn-claude-code-s05-s11-学习笔记
笔记·学习
程序猿乐锅19 小时前
【从0-1学习Python | 第七篇】Python 面向对象基础
开发语言·笔记·后端·python·学习·1024程序员节
fish_zzzz19 小时前
笔记--浅谈内存,存储空间,BIOS芯片,显卡GPU、VRAM(1)
笔记·1024程序员节
ACP广源盛1392462567319 小时前
PCIe Gen3 交换芯片选型笔记:多路扩展方案 IX7024@ACP 评估
笔记·硬件架构·pcie·国产芯片
深圳老胡20 小时前
STM32 开发中 Trae 内置模型怎么选:Seed、MiniMax、GLM、DeepSeek、Kimi、Qwen 全对比
笔记·stm32·单片机·嵌入式硬件·代码规范·1024程序员节
坤坤子吖20 小时前
C++继承:友元、静态成员、多继承与组合
开发语言·c++·笔记·学习·1024程序员节
Nuanyt21 小时前
Hot 100 刷题笔记 · 数组与哈希专题(3 题)
java·笔记·算法·leetcode·哈希算法·1024程序员节
破芽1 天前
learn-claude-code-s08-s09-学习笔记
笔记·学习