1

我写了一小段代码。像下面的东西

    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()。

4

3 回答 3

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的系统 Mutex 对象的包装器。命名互斥体是系统范围的并且跨进程可见。当您创建 .NET Mutex 对象并提供名称时,如果具有此名称的系统 Mutex 不存在,则会创建并包装到您获得的 .NET 对象中。如果之前已经创建了具有此名称的系统 Mutex,则此现有 Mutex 将被包装并作为新的 .NET Mutex 对象返回。

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

于 2013-02-15T01:01:56.667 回答
1

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

于 2013-02-15T01:08:20.740 回答
-1

编辑:我已经知道这个答案是不正确的。 佳沛解释如下。


没有机会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()

于 2013-02-14T22:32:32.757 回答