为什么没有方法在C#中获取信号量的多个许可?我想像这样使用我的信号量:
semaphore.Acquire(2);
答案 0 :(得分:5)
良好的api设计是一门艺术,只有少数人才能真正掌握。一个重要方面是强调共性。 .NET Semaphore类具有此功能,您可以使用WaitOne()
来获取信号量。就像你在所有同步类上一样。
通过了解遗漏的内容,它变得特别精美。自定义Aquire(n)
方法在该切割清单上会很高。这是一个非常麻烦的方法,Windows上的底层本机实现也不支持它。这产生了引发死锁的严重风险,这种死锁几乎无法调试,代码将挂在一个隐藏的方法中,这个方法循环,深埋在CLR内部。当需要中止代码时,这会增加很多语义来等待很多事情。您可以自由循环,一个简单的解决方法,当然,当您调试死锁时,您可以至少检查计数器。
答案 1 :(得分:4)
.Net Semaphore
对象是Win32 Semaphore对象的包装器。由于Win32信号量没有任何一次获取多个资源的机制,因此没有简单的方法在.Net Framework中提供它。
当然,微软可能已经在Win32信号量上实现了自己的抽象,但随后它们无法包含在WaitAll
调用中。 MS很可能从未考虑过实现此功能。
答案 2 :(得分:1)
您可以将自己的extention方法写入信号量类:
namespace Extentions
{
public static class SemaphoreExtentions
{
public static void Acquire(this Semaphore semaphore, int permits)
{
for (int i = 0; i < permits; ++i)
semaphore.WaitOne();
}
}
}
用法:
using Extentions;
//...
public void SomeMethod()
{
var sem = new Semaphore(10, 10);
sem.Acquire(6);
}
<强>更新强> 为了避免死锁:
public static void Acquire(this Semaphore semaphore, int permits)
{
lock (semaphore)
{
for (int i = 0; i < permits; ++i)
semaphore.WaitOne();
}
}
当然你不应该把这个信号量锁定在其他地方,因为它也可能导致死锁。另一种选择是将方法的签名更改为获取(此信号量信号量,int允许,对象同步)并锁定同步对象。
答案 3 :(得分:0)
如果您只是想检查许可证是否可用,而不需要阻止,则可以通过简单安全(无死锁)的方式实现。
public static bool Acquire (this Semaphore semaphore, int permits) {
for (int i = 0; i < permits; i++) {
/*
* If millisecondsTimeout is zero, the method does not block.
* It tests the state of the wait handle and returns immediately.
*/
if (!semaphore.WaitOne (0)) {
semaphore.Release (i);
return false;
}
}
return true;
}
可以轻松修改此内容以包含超时。但是,无限期地包含阻塞会更加困难(它需要信令,否则会导致繁忙的外部循环)。