SemaphorefullException - 由逻辑错误引发?

时间:2011-05-03 17:24:37

标签: c# multithreading

我有一个多线程应用程序,其中一个类使用信号量来控制读取和读取。写作。这似乎在大多数情况下工作得很好,但是我得到一些莫名其妙的semaphorefull异常抛出,表明我试图释放我不应该。问题是我已经完成了我的代码和工作。似乎无法找到导致这种情况发生的逻辑缺陷。

如果有人可以查看下面的示例代码,我将非常感激。让我知道我在哪里出错了,因为在这个阶段我觉得我开始发疯了。

请注意,“真正的”代码不只是有一个线程循环,而是非常接近

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

}

3 个答案:

答案 0 :(得分:3)

您将遇到的一个问题是,您正在为WorkClass的每个实例创建一个新的信号量。因此,如果您有三个WorkClass个实例,则会有三个单独的信号量。我认为您希望您的信号量为static,以便所有实例共享一个信号量。您将其称为_pool,因此我假设您希望所有实例都访问的共享资源数量有限。

我看不出您在问题中提供的代码如何抛出SemaphoreFullException。您确定您发布的代码在功能上等同于您遇到问题的代码吗?如果你编译并运行你发布的代码,你会得到那个例外吗?

答案 1 :(得分:2)

Semaphore IDisposableWaitHandle - 你需要WorkerClass Dispose当它Dispose - d。

public class WorkClass : IDisposable

using (WorkClass workClass = new WorkClass())

由于unDisposed Semaphore实例,您可能在加载时遇到了一些系统限制?这可能不是 问题,但它是 A 问题,无论您进行任何重新设计以使pool静态或其他单例机制。

答案 2 :(得分:0)

您在工作类之外传递信号量(包含在Token实例中)的事实可能表明您正在其他地方使用它,BeginReadEndRead

如果仅在WorkClass内使用信号量,我强烈建议您将其从Token中完全删除 - 将其设为私有静态字段(如Jim pointed out)并将其隐藏世界其他地方。