Reputation: 2146
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
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
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
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