C# 信号量(Semaphore)详细使用案例

文章目录

    • 简介
    • 信号量的工作原理
    • 使用场景
    • 使用示例
    • 其他使用实例
      • [1. 数据库连接池管理](#1. 数据库连接池管理)
      • [2. 文件读写同步](#2. 文件读写同步)
      • [3. 生产者消费者问题](#3. 生产者消费者问题)
      • [4. 打印任务队列同步](#4. 打印任务队列同步)
      • [5. Web服务器并发请求限制](#5. Web服务器并发请求限制)

简介

在C#中,信号量(Semaphore)是.NET框架提供的一个同步类,位于System.Threading命名空间下,用于控制并发访问特定资源的线程数量。它是一种更灵活的线程同步机制,通过维护一个计数器来管理资源的可用性。

信号量的工作原理

初始化时,可以指定一个初始计数值,这个值表示可以同时访问共享资源的线程数。

  • 当线程调用WaitOne()方法时,如果信号量计数器大于0,则计数器减1,并允许线程继续执行;若计数器为0,则线程被阻塞并等待其他线程释放信号量。
  • 通过调用Release()方法,可以增加信号量的计数值,从而允许一个或多个等待中的线程获取信号量并继续执行。

使用场景

  1. 资源池管理:例如,限制数据库连接池中同时活动的连接数,以防止过多连接导致系统过载。
  2. 互斥锁(Mutex)替代:当信号量初始化为1时,它相当于一个互斥锁,确保同一时间只有一个线程能访问临界区。
  3. 多线程同步:对于可同时由多个线程使用的有限资源,如许可、通道容量等,可以通过设置适当的信号量计数值来协调多个线程的并发访问。

使用示例

csharp 复制代码
using System.Threading;

// 创建一个最多允许5个线程同时访问的信号量
Semaphore semaphore = new Semaphore(5, 5); // 第一个参数是初始信号量,第二个参数是最大信号量

void AccessResource()
{
    // 尝试获取信号量
    semaphore.WaitOne();

    try
    {
        // 这里是临界区,只有拿到信号量的线程才能进入
        // 执行对共享资源的操作...
    }
    finally
    {
        // 资源操作完毕后,释放信号量
        semaphore.Release();
    }
}

// 在多个线程中调用AccessResource()函数
// ...

在上述代码中,Semaphore(5, 5)创建了一个信号量,初始和最大并发访问数均为5。当超过5个线程尝试访问资源时,额外的线程将会阻塞直到有其他线程完成操作并释放信号量。每个成功获取信号量的线程在完成资源访问后都会调用Release()将信号量递增,以便后续线程继续访问。

其他使用实例

1. 数据库连接池管理

csharp 复制代码
Semaphore connectionSemaphore = new Semaphore(10, 10); // 最多允许10个并发连接

void ExecuteQuery()
{
    connectionSemaphore.WaitOne();
    try
    {
        var connection = GetDatabaseConnection(); // 获取数据库连接
        // 执行SQL查询...
    }
    finally
    {
        ReleaseDatabaseConnection(connection); // 释放数据库连接
        connectionSemaphore.Release();
    }
}

// 多线程环境下,多个线程调用ExecuteQuery()函数执行数据库操作

2. 文件读写同步

csharp 复制代码
Semaphore fileSemaphore = new Semaphore(1, 1); // 文件操作为互斥,同一时间仅允许一个线程访问

void WriteToFile(string content)
{
    fileSemaphore.WaitOne();
    try
    {
        using (var writer = new StreamWriter("file.txt"))
        {
            writer.WriteLine(content);
        }
    }
    finally
    {
        fileSemaphore.Release();
    }
}

// 多线程环境下,同时写入文件但不会产生数据混乱

3. 生产者消费者问题

csharp 复制代码
Semaphore bufferSemaphore = new Semaphore(10, 10); // 缓冲区大小为10

void Producer()
{
    var item = CreateItem();
    bufferSemaphore.WaitOne();
    try
    {
        Buffer.Add(item); // 将产品放入缓冲区
    }
    finally
    {
        bufferSemaphore.Release();
    }
}

void Consumer()
{
    bufferSemaphore.WaitOne();
    try
    {
        var item = Buffer.Take(); // 从缓冲区取出产品进行消费
        Consume(item);
    }
    finally
    {
        bufferSemaphore.Release();
    }
}

// 生产者和消费者线程通过信号量控制对缓冲区的存取操作

4. 打印任务队列同步

csharp 复制代码
Semaphore printerSemaphore = new Semaphore(1, 1); // 打印机为独占资源

void PrintJob()
{
    printerSemaphore.WaitOne();
    try
    {
        SendToPrinter(JobQueue.Dequeue()); // 从打印任务队列中取出并发送打印任务
    }
    finally
    {
        printerSemaphore.Release();
    }
}

// 多线程环境下,打印机按顺序处理打印任务,避免任务冲突

5. Web服务器并发请求限制

csharp 复制代码
Semaphore requestSemaphore = new Semaphore(100, 100); // 同时处理的最大请求数为100

async Task HandleHttpRequest(HttpRequest request)
{
    requestSemaphore.WaitOne();
    try
    {
        await ProcessRequestAsync(request); // 处理HTTP请求
    }
    finally
    {
        requestSemaphore.Release();
    }
}

// Web服务器使用信号量限制同时处理的并发请求数量,防止过多请求导致系统过载

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)


​最后我们放松一下眼睛

相关推荐
可喜~可乐1 小时前
C# WPF开发
microsoft·c#·wpf
666和7775 小时前
C#的单元测试
开发语言·单元测试·c#
小码编匠6 小时前
WPF 星空效果:创建逼真的宇宙背景
后端·c#·.net
向宇it8 小时前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
yngsqq9 小时前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#
TENET信条10 小时前
day53 第十一章:图论part04
开发语言·c#·图论
anlog11 小时前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
向宇it13 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
仰望大佬00713 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
糖朝13 小时前
c#读取json
c#·json