c#信号量Semaphore只允许有限数量的线程进入临界区。信号量主要用于资源有限,我们必须限制使用线程的数量的场景。
Semaphore semaphoreObject = new Semaphore(initialCount: 0, maximumCount: 5);
信号量是存储在操作系统资源中的Int32变量。当使用int类型参数进行初始化信号量对象时,这个参数的数字值限制了可以进入临界区的线程数。 当线程进入临界区时,它将Int32变量的值减小为1,当线程从临界区退出时,它将Int32变量的值增加为1。 当Int32变量为0时,没有线程可以进入临界区。 下面是c#信号量初始化的语法。
Semaphore semaphoreObject = new Semaphore(initialCount: 0, maximumCount:
我们用两个参数初始化Semaphore :
最大计数定义了可以进入临界区的最大线程数。初始计数设置 Int32 变量值。例如,如果我们设置最大计数为 3,初始计数为 0。这意味着 3 个线程已经在临界区。如果我们将最大计数设置为 3,初始计数设置为 3,则意味着最多可以有 3 个线程进入临界区,并且临界区中当前没有线程.
在多个进程之间使用信号量
或者 semaphore 有另一个构造函数,它接受额外的字符串作为参数。该字符串参数是一个唯一的字符串,用于在多个进程之间使用信号量
以下是创建信号量的用法。
Semaphore semaphoreObject = new Semaphore(initialCount: 0, maximumCount: 5, name: "MyUniqueNameApp");
WaitOne 方法
线程可以通过 WaitOne 方法进入临界区。他们在信号量对象上调用了 WaitOne 方法。如果信号量维护的 Int32 变量大于 0,则允许调用线程进入。
以下是调用WaitOne 的方式。
semaphoreObject.WaitOne();
在信号量 WaitOne 方法的另一个重载中,我们可以通过时间间隔,线程可以等待从信号量获取信号。如果线程在指定的时间内没有收到信号,则返回 false 值
bool isSignalled = semaphoreObject.WaitOne(TimeSpan.FromSeconds(4));
在上面的例子中,如果调用线程在指定的 4 秒内没有收到信号,则返回 false。如果它接收到信号,则返回真。
Release 方法
当一个线程从临界区退出时,它必须调用 Release 方法来增加信号量对象维护的计数器。进而允许等待线程进入临界区
semaphoreObject.Release();
默认情况下,Release 方法只将计数器加 1。这意味着只有一个线程从临界区退出。我们还可以向 Release 方法传递一个参数来定义实际退出的线程数。
semaphoreObject.Release(3);
在上面的代码中,我们将 3 传递给 Release 方法。这将通知信号量对象实际上有 3 个线程从临界区退出。所以信号量对象将计数器增加 3。
在下面的示例中显示了如何将信号量对象与Console一起使用。要求限制可以同时使用 Printer 对象的线程数。为此,我们使用最大计数为 3 的信号量对象。
class Program
{
static void Main(string[] args)
{
Semaphore semaphoreObject = new Semaphore(initialCount: 3, maximumCount: 3, name: "PrinterApp");
Printer printerObject = new Printer();
for (int i = 0; i < 20; ++i)
{
int j = i;
Task.Factory.StartNew(() =>
{
semaphoreObject.WaitOne();
printerObject.Print(j);
semaphoreObject.Release();
});
}
Console.ReadLine();
}
}
class Printer
{
public void Print(int documentToPrint)
{
Console.WriteLine("Printing document: " + documentToPrint);
Thread.Sleep(TimeSpan.FromSeconds(5));
}
}
初始化信号量对象,并设置了初始化数和最大数,并给出唯一名称“PrinterApp”。以从 0 到 20 的运行开始 for 循环。使用 TaskFactory 启动线程
每个线程在使用Printer 对象之前都会调用semaphore 对象的WaitOne() 方法。这将限制使用Printer对象的线程数。使用Printer对象后,每个线程调用 Release() 方法来增加信号量的计数器以使更多线程可进入临界区