3

我不确定如何解决这个问题。我有一个这样声明的互斥锁:

public class MyNamedLock
{
    private Mutex mtx;
    private string _strLkName;

    public MyNamedLock(string strLockName)
    {
        _strLkName = strLockName;
        //...

        mtx = new Mutex(false, _strLkName, out bCreatedNew, mSec);
    }

    public bool enterLockWithTimeout(int nmsWait = 30 * 1000)
    {
        _nmsWaitLock = nmsWait;

        //Wait
        return mtx.WaitOne(nmsWait);
    }

    public void leaveLock()
    {
        _nmsWaitLock = 0;

        //Release it
        mtx.ReleaseMutex();
    }
}

然后在 ASP.NET 页面中使用它:

public class MyClass
{
    private MyNamedLock gl;

    public MyClass()
    {
        gl = new MyNamedLock("lock name");

    }


    public void funct()
    {
        try
        {
            //Enter lock
            if (gl.enterLockWithTimeout())
            {
                //Do work
            }
            else
                throw new Exception("Failed to enter lock");
        }
        finally
        {
            //Leave lock
            gl.leaveLock();
        }
    }
}

这段代码在我的开发环境中没有给我任何麻烦,但在生产中它有时会抛出这个异常:

对象同步方法是从未同步的代码块中调用的。

描述有点模糊,但只是进行跟踪我发现该mtx.ReleaseMutex();部分引发了异常。这是什么意思以及如何解决它?

4

2 回答 2

1

在您的 finally 块中,您将释放互斥锁,无论您是否在 try 块中实际获得了它。

try
{
    //Enter lock
    if (gl.enterLockWithTimeout())
    {
        //Do work
    }
    else throw new Exception("Failed to enter lock");
}
finally
{
    //Leave lock
    gl.leaveLock();
}

如果gl.enterLockWithTimeout返回 false,您将抛出异常,然后尝试释放 finally 块中的锁。

于 2013-03-14T23:33:13.327 回答
1

您的课程以及使用它的方式存在一些问题。

  1. 仅当您先前已锁定时才必须释放互斥锁(这是您的错误)
  2. 您需要关闭并处置您打开的互斥锁
  3. 最好在您使用它之前创建它,而不是在您创建类时创建它MyClass

因此,我建议首先将您的课程更改为:

public class MyNamedLock
{
    private Mutex mtx = null;
    private string _strLkName;

    // to know if finally we get lock
    bool cNeedToBeRelease = false;

    public MyNamedLock(string strLockName)
    {
        _strLkName = strLockName;
        //...

        mtx = new Mutex(false, _strLkName, out bCreatedNew, mSec);
    }

    public bool enterLockWithTimeout(int nmsWait = 30 * 1000)
    {
        _nmsWaitLock = nmsWait;
        bool cLock = false;
        try
        {
            cLock = mtx.WaitOne(nmsWait, false);
            cNeedToBeRelease = cLock;    
        }
        catch (AbandonedMutexException)
        {
            // http://stackoverflow.com/questions/654166/wanted-cross-process-synch-that-doesnt-suffer-from-abandonedmutexexception
            // http://msdn.microsoft.com/en-us/library/system.threading.abandonedmutexexception.aspx
            cNeedToBeRelease = true;
        }
        catch (Exception x)
        {
            // log the error
            Debug.Fail("Check the reason of fail:" + x.ToString());
        }            

        return cLock;        
    }

    public void leaveLock()
    {
        _nmsWaitLock = 0;

        if (mtx != null)
        {
            if (cNeedToBeRelease)
            {
                try
                {
                    mtx.ReleaseMutex();
                    cNeedToBeRelease = false;    
                }
                catch (Exception x)
                {
                    Debug.Fail("Check the reason of fail:" + x.ToString());
                }
            }

            mtx.Close();
            mtx.Dispose();
            mtx = null;
        }
    }
}

这是您必须调用该类的方式:

public class MyClass
{
    public MyClass()
    {
    }


    public void funct()
    {
        var gl = new MyNamedLock("lock name");
        try
        {
            //Enter lock
            if (gl.enterLockWithTimeout())
            {
                //Do work
            }
            else
                throw new Exception("Failed to enter lock");
        }
        finally
        {
            //Leave lock
            gl.leaveLock();
        }
    }
}
于 2013-03-15T00:22:27.297 回答