C#信号量用法简单示例

当我们需要对一个或多个资源进行控制时,可以使用信号量。信号量是一种同步原语,它可以被用来跟踪资源的可用性。在这篇文章中,我们将会讲解C#中的信号量用法,包括信号量的基本操作和信号量用法的示例。

基本用法

在C#中,信号量可以通过System.Threading命名空间的Semaphore类来实现。Semaphore类封装了Windows内核对象,可以根据需要增加或删除元素。常用的构造函数有以下两种:

  • Semaphore(int initialCount, int maximumCount):初始化一个 Semaphore 实例,它同时限制了同时访问信号量的线程数量。initialCount参数指定最初可使用的锁定数量;maximumCount指定信号量的最大值,最大值不能小于initialCount值。
  • Semaphore(int initialCount, int maximumCount, string name, out bool createdNew):初始化具有指定名称的 Semaphore 对象,如果 Semaphore 对象不存在,则新建一个。name参数指定 Semaphore 实例的名称,createdNew参数指示是否创建了 Semaphore 实例。

Semaphore类有以下一些常见的方法:

  • WaitOne():尝试减小 Semaphore 对象的可用计数器。如果当前可用的计数器为 0,则会阻止调用线程,直到 Semaphore 可用为止。
  • WaitForMultipleObjects(IntPtr[], bool, int):暂停当前线程,直到在多个等待线程句柄中的一个变为终止状态或等待线程时间到达限制。在接收到一个等待的句柄后,方法会将其他等待的句柄从等待状态下移除。
  • Release():增加 Semaphore 对象计数器的值,从而允许创建者线程使用 Semaphore。

接下来是Semaphore类的一个简单示例:

using System;
using System.Threading;

class SemaphoreDemo
{
    static Semaphore _pool = new Semaphore(0, 2);

    static void Main(string[] args)
    {
        for (int i = 1; i <= 5; i++)
        {
            Thread t = new Thread(new ParameterizedThreadStart(Worker));
            t.Start(i);
        }

        Console.ReadLine();
    }

    static void Worker(object id)
    {
        Console.WriteLine("Worker {0} 开始执行...", id);
        _pool.WaitOne();
        Console.WriteLine("Worker {0} 开始使用资源...", id);
        Thread.Sleep(5000);
        Console.WriteLine("Worker {0} 使用资源结束...", id);
        _pool.Release();
    }
}

在这个示例中,Semaphore对象的最大计数器值被设置为2,以限制最多只有两个线程可以同时访问受信号量保护的资源。五个不同的工作线程被创建并启动,它们共享两个信号量。当一个工作线程需要访问资源时,它会等待另一个线程释放一个信号量,然后才能继续执行。

示例1:控制并发访问Web API

一个常见的示例是,你的应用程序需要同步地访问一个Web API。由于API的限制,你最多只能有三个并发连接。为了管理你的连接,你可以使用一个信号量。

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;

class WebApiManager
{
    static Semaphore _semaphore;

    static WebApiManager()
    {
        _semaphore = new Semaphore(3, 3);
    }

    public static async Task<string> GetDataAsync(string url)
    {
        _semaphore.WaitOne();

        try
        {
            using (var client = new HttpClient())
            {
                var response = await client.GetStringAsync(url);
                return response;
            }
        }
        finally
        {
            _semaphore.Release();
        }
    }
}

在上面的示例中,使用了一个Semaphore对象来限制API调用的并发量。Semaphore对象的初始计数是3,因此最多只能有3个线程同时调用GetDataAsync()方法。在传入url参数之后,线程通过调用Semaphore对象的WaitOne()方法来等待可用的信号量。如果当前没有可用的信号量,线程将被阻塞,直到有一个信号量可用或者超时。当信号量可用时,线程可以继续执行,使用HttpClient发起API调用。当线程完成调用时,它调用信号量的Release()方法来释放一个信号量。

示例2:实现资源池

另一个示例是,你需要管理一个资源池,例如数据库连接、网络连接等。由于这些资源是有限的,你需要一个机制来限制资源的并发使用量。你可以使用一个信号量来实现这个功能。

class ResourcePool<T>
{
    private Stack<T> _resources;
    private Semaphore _semaphore;

    public ResourcePool(IEnumerable<T> resources, int maxCount)
    {
        _resources = new Stack<T>(resources);
        _semaphore = new Semaphore(maxCount, maxCount);
    }

    public T Acquire()
    {
        _semaphore.WaitOne();

        T resource;

        lock (_resources)
        {
            resource = _resources.Pop();
        }

        return resource;
    }

    public void Release(T resource)
    {
        lock (_resources)
        {
            _resources.Push(resource);
        }

        _semaphore.Release();
    }
}

在上面的示例中,使用一个Semaphore对象来限制ResourcePool对象中的资源并发使用量。在构造函数中,你需要指定初始资源列表和Semaphore最大计数器值。在Acquire()方法中,线程等待一个可用的信号量,并且从资源池中弹出一个可用的资源。在Release()方法中,线程将资源放回资源池,并释放一个信号量。

这样,就实现了一个Thread-Safe的资源池,可以在多线程环境下被安全地访问。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#信号量用法简单示例 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • C# 基于消息发布订阅模型的示例(上)

    让我来详细讲解一下「C# 基于消息发布订阅模型的示例(上)」的完整攻略。 什么是消息发布订阅模型? 消息发布订阅模型是一种系统架构模式,它支持应用程序之间的松耦合通信,允许一个事件的发布者将事件发送给多个订阅者。在这种模式中,发布者并不知道订阅者的存在,订阅者则会接收到发布者发布的所有事件。 实现消息发布订阅模型的步骤 以下是实现消息发布订阅模型的基本步骤:…

    C# 2023年5月31日
    00
  • C#实现Winform版计算器

    这里是C#实现Winform版计算器的完整攻略: 1. 确定项目的需求和功能 在开始任何项目之前,首先要确定项目的需求和功能,这样可以帮助我们更好地规划和实施项目。对于一个计算器,我们至少需要实现以下功能: 基本运算:加减乘除 清除:清空当前输入和结果 回退:撤销上一步输入 小数点:支持小数计算 防止错误输入:例如除以0等情况 确定以上需求和功能后,我们可以…

    C# 2023年6月6日
    00
  • .net开发中几个重要的认识误区小结

    拜会网站读者,相信在学习和使用.net开发框架的过程中,大家会遇到很多的问题和疑惑,今天我就和大家一起来详细讲解几个在.net开发中容易产生的认识误区,希望能给大家带来一些帮助。 認識誤區一: C# 和 .NET 等價 许多人在刚开始学习.net开发框架时,会把C#语言和.NET框架等同起来,甚至将它们视为相同的事物,而事实上,C#只是.NET框架中的一种编…

    C# 2023年6月3日
    00
  • C# 获取属性名的方法

    获取 C# 对象的属性名可能是我们在开发中需要经常使用到的操作。下面是获取 C# 对象属性名的两种常见方式: 通过字符串常量 我们可以通过字符串常量获取对应属性名。首先我们需要在对象中声明属性,然后使用字符串常量将属性名称与属性值绑定。下面是一个使用字符串常量获取属性名的示例代码: using System; namespace AttributeDemo …

    C# 2023年5月31日
    00
  • 简单了解Java方法的定义和使用实现

    下面以Markdown格式为例,分别对Java方法的定义和使用实现进行详细讲解。 一、Java方法的定义 在Java中,方法是一组执行特定任务的语句集合。它提供了一种封装代码、组织代码和重复利用代码的功能。Java方法的定义需要包含以下几个部分: 1. 方法签名 方法签名是指方法名和参数列表的组合,它是方法的唯一标识。方法签名的格式如下: 修饰符 返回类型 …

    C# 2023年5月15日
    00
  • 用 C# 编写一个停放在任务栏上的图标程序

    下面是用C#编写一个停放在任务栏上的图标程序的完整攻略: 步骤一:创建项目 打开Visual Studio 新建一个Windows 窗体应用程序项目。 在解决方案资源管理器中双击 Form1.cs 文件以打开窗体设计器。 将工具箱中的 NotifyIcon 控件拖到窗口设计器窗口中,这个控件将是我们后面实现任务栏图标功能的主角。 步骤二:实现图标控制功能 给…

    C# 2023年6月7日
    00
  • C#操作INI文件的方法详解

    C#操作INI文件的方法详解 什么是INI文件? INI文件(.INI文件)是Windows操作系统中常见的配置文件格式,它的简单文本格式使得多个应用程序和操作系统可以读取并修改它,通常用于保存程序或应用程序的配置信息。INI文件中的数据通常被组织为段落和参数的形式,在应用程序或操作系统中也可以通过读写INI文件来保存和读取配置信息。 C#中操作INI文件的…

    C# 2023年6月1日
    00
  • C#的通用DbHelper类(支持数据连接池)示例详解

    C#的通用DbHelper类(支持数据连接池)示例详解 1. 概述 DbHelper是一种常用的C#代码封装方式,它用于简化数据库操作的代码,提高代码的可读性、可维护性,减少开发者的工作量。本文将详细介绍如何编写一个通用的DbHelper类,可以支持数据连接池,方便多个线程同时进行数据库操作。 2. 数据库连接配置 为了使DbHelper类支持数据连接池,我…

    C# 2023年6月2日
    00
合作推广
合作推广
分享本页
返回顶部