为什么没有Javalike信号量在C#中获得多个许可?

时间:2013-12-05 13:17:03

标签: c# concurrency

为什么没有方法在C#中获取信号量的多个许可?我想像这样使用我的信号量:

semaphore.Acquire(2);

4 个答案:

答案 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;
}

可以轻松修改此内容以包含超时。但是,无限期地包含阻塞会更加困难(它需要信令,否则会导致繁忙的外部循环)。