信号量 - 初始计数有什么用?

时间:2011-01-16 17:03:48

标签: c# multithreading concurrency semaphore

http://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim.aspx

要创建信号量,我需要提供初始计数和最大计数。 MSDN声明初始计数为 -

  

最初的请求数量   可以授予的信号量   同时进行。

虽然它声明最大数量是

  

最大请求数   可以授予的信号量   同时进行。

我可以理解,最大计数是可以同时访问资源的最大线程数。但是,初始计数的用途是什么?

如果我创建一个初始计数为0且最大计数为2的信号量,则我的线程池线程都不能访问该资源。如果我将初始计数设置为1并将最大计数设置为2,则只有线程池线程可以访问该资源。只有当我将初始计数和最大计数都设置为2时,2个线程才能同时访问资源。那么,我对初始计数的重要性感到困惑吗?

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 2); //all threadpool threads wait
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 2);//only one thread has access to the resource at a time
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2, 2);//two threadpool threads can access the resource concurrently

7 个答案:

答案 0 :(得分:59)

是的,当初始数字设置为0时 - 所有线程将在您增加“CurrentCount”属性时等待。您可以使用Release()或Release(Int32)来完成它。

发布(...) - 将增加信号量计数器

等待(...) - 将减少它

您不能将计数器(“CurrentCount”属性)增加到大于您在初始化中设置的最大计数。

例如:

SemaphoreSlim^ s = gcnew SemaphoreSlim(0,2); //s->CurrentCount = 0
s->Release(2); //s->CurrentCount = 2
...

s->Wait(); //Ok. s->CurrentCount = 1
...

s->Wait(); //Ok. s->CurrentCount = 0
...

s->Wait(); //Will be blocked until any of the threads calls Release()

答案 1 :(得分:47)

  

所以,我对初始计数的重要性感到困惑?

这里可能有用的一点是,Wait递减信号量计数,Release递增它。

initialCount是将立即允许的资源访问次数。或者,换句话说,它是在信号量被实例化后立即调用Wait而不立即阻塞的次数。

maximumCount是信号量可以获得的最高计数。假设Release计数为零,可以在不抛出异常的情况下调用initialCount的次数。如果将initialCount设置为与maximumCount相同的值,则在实例化信号量后立即调用Release将引发异常。

答案 2 :(得分:6)

您希望一次能够访问资源多少个线程?将初始计数设置为该数字。如果该数字在程序的整个生命周期中永远不会增加,请将最大计数设置为该数字。这样,如果您在释放资源方面遇到编程错误,程序将崩溃并通知您。

(有两个构造函数:一个只接受初始值,另一个接受最大计数。使用适当的。)

答案 3 :(得分:1)

这样当当前线程创建信号量时,它可以从一开始就声明一些资源。

答案 4 :(得分:1)

如果您希望一段时间没有线程访问您的资源,您将初始计数传递为0,并且当您希望在创建信号量后立即授予对所有这些资源的访问权限时,您传递初始计数值等于达到最大数量。例如:

hSemaphore = CreateSemaphoreA(NULL, 0, MAX_COUNT, NULL) ;

//Do something here
//No threads can access your resource

ReleaseSemaphore(hSemaphore, MAX_COUNT, 0) ;

//All threads can access the resource now

在MSDN文档中引用 - “ReleaseSemaphore的另一个用途是在应用程序初始化期间。应用程序可以创建初始计数为零的信号量。这会将信号量的状态设置为无信号并阻止所有线程访问受保护资源。当应用程序完成初始化时,它使用ReleaseSemaphore将计数增加到其最大值,以允许正常访问受保护资源。“

答案 5 :(得分:1)

信号量可用于保护资源池。我们使用资源池来重用创建昂贵的东西-例如数据库连接。

因此,初始计数是指池中池中可用资源的数量。 开始某些过程。当您阅读代码中的initialCount时,应该考虑创建此资源池需要付出多少努力。

  

我真的对初始计数的意义感到困惑吗?

Initial count = Upfront cost

因此,根据应用程序的使用情况,此值可能会对应用程序的性能产生重大影响。这不仅仅是一些任意数字。

您应该仔细考虑所创建的内容,创建的成本以及立即需要的数量。从字面上看,您应该能够绘制出此参数的最佳值,并应该考虑使其可配置,以便使过程的性能适应执行时间。

答案 6 :(得分:0)

正如MSDN在备注部分解释的那样:

  

如果initialCount小于maximumCount,则效果与当前线程调用WaitOne(maximumCount减去initialCount)次数相同。如果您不想为创建信号量的线程保留任何条目,请对maximumCount和initialCount使用相同的数字。

因此,如果初始计数为0且max为2,则好像主线程已经两次调用WaitOne,因此我们已达到容量(信号量计数现在为0)并且没有线程可以进入信号量。类似地,如果初始计数为1且max为2,则WaitOnce已被调用一次,并且在我们再次达到容量之前只能有一个线程进入,依此类推。

如果初始计数使用0,我们总是可以调用Release(2)将信号量计数增加到max,以允许最大线程数获取资源。