据我所知,无需先使用WaitOne
获取锁,线程就可以在信号量上释放。
因此,如果我们有线程A,B和C以及信号灯,则A和B调用WaitOne
,请获取锁并开始进行业务。
线程C随即发出,只在信号量上调用Release
。
这应该使信号量的计数增加1。这是否意味着信号量将终止A或B或仅允许第三个线程获取锁并在其池中拥有3个线程,即使最大为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