信号量如何从另一个线程释放?

时间:2019-01-28 11:34:23

标签: c# multithreading semaphore

据我所知,无需先使用WaitOne获取锁,线程就可以在信号量上释放。

因此,如果我们有线程A,B和C以及信号灯,则A和B调用WaitOne,请获取锁并开始进行业务。
线程C随即发出,只在信号量上调用Release

这应该使信号量的计数增加1。这是否意味着信号量将终止A或B或仅允许第三个线程获取锁并在其池中拥有3个线程,即使最大为2? >

2 个答案:

答案 0 :(得分:1)

您可以将信号量视为阻塞队列的特例:信号量的“计数”是队列中项目的数量,但项目本身不包含任何信息。就像允许任何线程将项目放入阻塞队列,允许任何线程将项目取出一样,任何线程都可以增加或减少信号量。

答案 1 :(得分:1)

考虑

var semaphore = new SemaphoreSlim(2);

这意味着此刻的信号量只有2个执行时隙,但是要记住,它只是执行时隙的初始编号(对于同时授予请求的请求)。

因此,如果我们将A,B,C线程生成为具有2个执行插槽的信号量,则将执行前两个线程,并且C线程将排队,直到代码中的其他人将信号量表示为可以再添加一个执行插槽。

当有人说可以执行队列中的下一个线程时,无论其他线程如何,都将执行C。


一些技术示例:

(正如我在@ dmitri-nesteruk的课程中看到的那样)

可用个执行槽的总数由CurrentCount表示。

每次要执行线程时,它都会询问信号量是否具有可用的执行插槽(带有CurrentCount > 0),如果为true,请随时执行自己的操作,如果没有进入队列,则为空。

使信号量如此混乱的原因是CurrentCount的值可以减小也可以增大。

  • 每次Wait()被一个a调用时,它就会减少1。 线程,这意味着可用插槽减少了一个 并且一个线程正在执行。

  • 每次Release(1)被使用时,它增加一个(或多个)。 在代码中的其他地方调用,这意味着还有一个 可用的执行插槽,因此信号灯内部的第一个线程 队列正在执行(不会终止其他队列)。

在此示例中,我们产生了3个线程,但是只有前两个线程将被执行,直到有人告诉信号量他可以通过将CurrentCount增加为Release(1)来释放另一个执行时隙。 / p>

for (int i = 0; i < 3 ; i++)
{
    Task.Factory.StartNew(() => 
    {
        Console.WriteLine($"Spawning task: {Task.CurrentId}");
        semaphore.Wait(); //CurrentCount--
        Console.WriteLine($"Executing task: {Task.CurrentId}");
    });
}


while (semaphore.CurrentCount <= 2)
{
    Console.ReadKey();
    Console.WriteLine("Key pressed");
    semaphore.Release(1); //CurrentCount++
}

输出:

Spawning task: A
Spawning task: B
Spawning task: C
Executing task: A
Executing task: B
.....
Key pressed
Executing task: C