关于Mutex Type的WaitOne()方法

时间:2013-02-14 04:46:31

标签: c# mutex waitone

我写了一小段代码。 类似下面的内容

    public static void SetLicence1()
    {
            Console.WriteLine("Setting Aspose Licence in Thread1 ");
            Console.WriteLine(SetAsposeLicense());
    }

    public static void SetLicence2()
    {
        Console.WriteLine("Setting Aspose Licence in Thread2 ");
        Console.WriteLine(SetAsposeLicense());
    }

    public static bool SetAsposeLicense()
    {
        try
        {
            //Declare Mutex variable:            
            using (Mutex mutex = new System.Threading.Mutex(false, "Test"))
            {
                    mutex.WaitOne(TimeSpan.FromSeconds(5));
                    var objLic = new License();
                    objLic.SetLicense(@"C:\Nivedita\License\Aspose.Cells.lic");
                    mutex.ReleaseMutex();
            }
            return true;
        }
        catch(Exception ex)
        {
               Console.WriteLine(ex.StackTrace);               
               return false;
        }
    }       
}

public class TestClass
{
    public static void Main()
    {
        Thread tid1 = new Thread(new ThreadStart(ThreadClass.SetLicence1));
        Thread tid2 = new Thread(new ThreadStart(ThreadClass.SetLicence2));

        tid1.Start();
        tid2.Start();

        Console.Read();
    }
}

这段代码工作得很好。但是我的问题是,WaitOne()方法是否有可能陷入进程中或跨进程并且互斥对象不会被释放?虽然我使用过mutex.ReleaseMutex()。

3 个答案:

答案 0 :(得分:2)

首先,你的意图并不十分明确。如果您只是想确保两个线程无法同时设置许可证,则需要以下内容:

static object s_lock = new object();

public static bool SetAsposeLicense()
{
    try
    {
        lock (s_lock)
        {
            var objLic = new License();
            objLic.SetLicense(@"C:\Nivedita\License\Aspose.Cells.lic");

        }
        return true;
    }
    catch(Exception ex)
    {
           Console.WriteLine(ex.StackTrace);               
           return false;
    }
}       

您注意到此处没有超时5秒。如果你想等待5秒并设置许可,无论,如果另一个线程已经完成(基本上你的问题中的代码是什么),而不是搞乱互斥,你最好这样做(但我难以理解,你为什么要这样做:

private static object s_lock = new object();

public static bool SetAsposeLicense()
{
    if (Monitor.TryEnter(s_lock, TimeSpan.FromSeconds(5)))
    {
        try 
        {
            return SetLicenseInternal(); 
        }
        finally 
        {
            Monitor.Exit(s_lock);
        }
    }
    return SetLicenseInternal(); 
}

public static bool SetLicenseInternal()
{
    try
    {
        var objLic = new License();
        objLic.SetLicense(@"C:\Nivedita\License\Aspose.Cells.lic");
        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.StackTrace);
        return false;
    }
}

使用Monitor对象比使用互斥锁更加“原生”,因为你不需要交叉处理,所以它更适合这里。

就Mutex而言,它是针对.NET浮出水面system Mutex object的包装器。命名互斥锁是系统范围的,并且在整个过程中可见。当您创建.NET Mutex对象并提供名称时,如果具有此名称的系统Mutex不存在,则会创建它并将其包装到您获得的.NET对象中。如果之前已创建具有此名称的系统Mutex,则此现有Mutex将作为新的.NET Mutex对象进行包装并返回。

我认为你不应该在你的场景中使用互斥锁。

答案 1 :(得分:1)

如果持有它的进程退出而未释放它,

WaitOne将抛出AbandondMutexException。即使使用try / finally块,如果您在visual studio中的错误位置停止调试或使用任务管理器结束该过程,仍然可能发生这种情况,因此您应该处理此情况重新锁定互斥锁或退出应用程序。请注意,如果由于抛出异常而未获取锁定,则也会抛出对release的调用。

答案 2 :(得分:-1)

编辑:我知道这个答案不正确。 zespri解释如下。


mutex块没有被释放的可能性,因为using块一结束就会被释放。没有其他任何东西可以看到mutex,因为它的范围是该方法。在这里意识到你有两个独立的Mutex个对象,一个在Thread1中,一个在Thread2中。这只是Mutex的错误使用。

如果您需要Mutex,请尝试以下方式:

private static Mutex mutex = new Mutex(false, "Test");

public static bool SetAsposeLicense()
{
    try
    {
        if (!mutex.WaitOne(TimeSpan.FromSeconds(5))
        {
            throw new TimeoutException("Aspose license registration timed out.");
        }
        try
        {
            var objLic = new License();
            objLic.SetLicense(@"C:\Nivedita\License\Aspose.Cells.lic");
            return true;
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex.StackTrace);
        return false;
    }
}

的变化:

  • 使mutex成为一个类成员,以便所有线程都可以看到相同的Mutex

  • 检查mutex是否已被释放,或者是否已超时。

  • 如果设置许可证引发异常,则添加嵌套的try/finally块以确保释放mutex。嵌套是必需的,因为ReleaseMetux()只能由成功调用WaitOne()的线程调用。