Johnv2020
Johnv2020

Reputation: 2146

SemaphorefullException - thrown by logic error?

I have a multithreaded application, of which one of the classes uses a semaphore to control reading & writing. This seems to work fine most of the time, however I'm getting some inexplicable semaphorefull exceptions thrown, indicating that I'm trying to release when I shouldn't be. The problem is I've been over my code & can't seem to find a flaw in the logic which would cause this to happen.

I would be really grateful if someone could take a look at the sample code below & let me know where I'm going wrong as at this stage I think I'm beginning to go mad..

Please note that the "real" code doesn't just have a loop of threads but its pretty close

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            Thread t = new Thread(() => ThreadA());
            t.Start();
        }            
    }

    /// <summary>
    /// Run the methods in the worker class
    /// </summary>
    private static void ThreadA()
    {
        Token token = null;
        WorkClass workClass = new WorkClass();
        try
        {
            workClass.BeginRead(out token, "A");                
        }
        finally
        {
            workClass.EndRead(token);
        }
    }       
}

/// <summary>
///  this class does the actual work
/// </summary>
public class WorkClass
{
    private Semaphore _pool = new Semaphore(2, 2);

    public void BeginRead(out Token token, string s)
    {
        Semaphore sem = null;
        try
        {
            // wait for the main semaphore to signal
            _pool.WaitOne();
            // set local semaphore equal to main
            sem = _pool;
            //simulate work
            Thread.Sleep(100);
        }
        finally
        {
            //return the token with the semaphore
            token = new Token(sem, s);
        }
    }

    public void EndRead(Token token)
    {
        try
        {
            // do some more work
        }
        finally
        {
            // release the semaphore if not null
            if (null != token.signal)
            {
                token.signal.Release();
            }
        }
    }    
}


public class Token
{
   internal readonly Semaphore signal;
   internal readonly string s;

    internal Token(Semaphore _signal, string _s)
    {
        this.s = _s;
        this.signal = _signal;
    }

}

Upvotes: 0

Views: 3126

Answers (3)

Steve Townsend
Steve Townsend

Reputation: 54148

Semaphore is IDisposable through WaitHandle - you need to make your WorkerClass Dispose it when it's Dispose-d of itself.

public class WorkClass : IDisposable

using (WorkClass workClass = new WorkClass())

Perhaps you are hitting some system limit under load due to unDisposed Semaphore instances? This may not be THE problem but it is A problem, regardless of any redesign you do to make pool static, or other singleton mechanism.

Upvotes: 2

vgru
vgru

Reputation: 51224

The fact that you are passing the semaphore outside of your worker class (wrapped in a Token instance) may indicate that you are using it somewhere else, other that BeginRead and EndRead.

If semaphore is used only inside the WorkClass, I would strongly recommend removing it from the Token completely - make it a private static field (as Jim pointed out) and hide it from the rest of the world.

Upvotes: 0

Jim Mischel
Jim Mischel

Reputation: 133995

One problem you're going to run into here is that you're creating a new semaphore for each instance of the WorkClass. So if you have three WorkClass instances, there will be three separate semaphores. I think you want your semaphore to be static, so that all instances share the one semaphore. You call it _pool, so I assume there's a limited number of shared resources that you want all instances to access.

I don't see how the code you presented in your question can throw a SemaphoreFullException. Are you certain that the code you posted is functionally equivalent to the code that you're having trouble with? If you compile and run the code that you posted, do you get that exception?

Upvotes: 3

Related Questions