Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why there is no Javalike semaphore acquiring multiple permits in C#?

Tags:

c#

concurrency

Why there is no method for acquiring multiple permits on semaphore in C#? I want to use my semaphore like this:

semaphore.Acquire(2);
like image 278
Mixer Avatar asked Dec 05 '13 13:12

Mixer


3 Answers

Good api design is a fine art, truly mastered only by a few. One important aspect is to emphasize commonality. The .NET Semaphore class has that, you use WaitOne() to acquire the semaphore. Like you do on all of the synchronization classes.

And it becomes especially a fine art by knowing what to leave out. A custom Aquire(n) method would be high on that cut list. It is a very troublesome method, the underlying native implementation on Windows doesn't support it either. Which produces the serious risk of inducing deadlock that's next to impossible to debug, the code would be hung inside an invisible method that's looping, buried deep inside the CLR. Which adds lots of semantics to waits that matter a great deal when code needs to be aborted. You're free to loop yourself, a simple workaround and of course well visible when you debug a deadlock, you can at least inspect the counter.

like image 62
Hans Passant Avatar answered Nov 14 '22 21:11

Hans Passant


The .Net Semaphore object is a wrapper around the Win32 Semaphore object. Since the Win32 semaphores don't have any mechanism to acquire multiple resources at once, there is no easy way to provide it in the .Net Framework.

Of course it's possible that Microsoft could have implemented their own abstraction over Win32 semaphores, but then they couldn't be included in a WaitAll call. It's quite likely that MS never even considered implementing this feature.

like image 42
Gabe Avatar answered Nov 14 '22 21:11

Gabe


You may write your own extention method to Semaphore class:

namespace Extentions
{
    public static class SemaphoreExtentions
    {

        public static void Acquire(this Semaphore semaphore, int permits)
        {
           for (int i = 0; i < permits; ++i)
               semaphore.WaitOne();
        }
    }
}

Usage:

using Extentions;

//...

public void SomeMethod()
{
    var sem = new Semaphore(10, 10);
    sem.Acquire(6);
}

Update To avoid deadlocks:

public static void Acquire(this Semaphore semaphore, int permits)
{
    lock (semaphore)
    {
        for (int i = 0; i < permits; ++i)
            semaphore.WaitOne();        
    }
}

Of course you shouldn't lock this semaphore somewhere else because it may cause deadlocks too. Another option is to change signature of the method to Acquire(this Semaphore semaphore, int permits, object sync) and lock sync object.

like image 45
Deffiss Avatar answered Nov 14 '22 21:11

Deffiss