Search code examples
c#multithreadinglockingsemaphorerace-condition

Why are these 4 threads locking up when using a semaphore?


In a system which may have many, many threads, I am trying to ensure that only four instances of a class are instantiated at a time and maybe released after 5-60 seconds. The instances are created at the start of each thread and destroyed when the process in the thread ends.

I also want to prevent only one instance being constructed at a time. So my logic is to use a lock during Object instantiation but also wrap the overall thread logic with a semaphore.

private static readonly object padlock = new object();
private static readonly Semaphore mutablelock = new Semaphore(0, 4);

// called at the start of a long running thread
public static Object GetNewInstance()
{
    // semaphore used to prevent more than 4 objects from existing at any time
    mutablelock.WaitOne();

    // lock used to prevent more than one object being instantiated at a time
    lock (padlock)
    {
        var instance = new Object();
        return instance;
    }
}

// called at the end of a long running thread
public static void ReleaseInstance()
{
    mutablelock.Release();
}

The program has four threads which (when viewed with debug stop points) each stop at the mutablelock.WaitOne(); line and never progress any further.


Solution

  • You're constructing your Semaphore in such a way that all entries have been reserved. The Semaphore constructor taking two arguments has this to say:

    If initialCount is less than maximumCount, the effect is the same as if the current thread had called WaitOne (maximumCount minus initialCount) times. If you do not want to reserve any entries for the thread that creates the semaphore, use the same number for maximumCount and initialCount.

    So make this change:

    private static readonly Semaphore mutablelock = new Semaphore(4, 4);