Nivedita
Nivedita

Reputation: 11

Regarding WaitOne() method of Mutex Type

I have written a small piece of code. something like below

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

This piece of code is working perfectly fine. But here my question is that is there any chance for the WaitOne() method can gets stuck in or across the processes and the mutex object doesnt get released? Although I have used mutex.ReleaseMutex().

Upvotes: 1

Views: 7635

Answers (3)

Yaur
Yaur

Reputation: 7452

WaitOne will throw an AbandondMutexException if the process that was holding it exits without releasing it. Even with a try/finally block it is still possible for this to happen if you stop debugging in the wrong place in visual studio or use task manager to end the process, so you should handle this case either relocking the mutex or exiting the application. Note that the call to release will also throw if the lock wasn't acquired due to the thrown exception.

Upvotes: 1

Andrew Savinykh
Andrew Savinykh

Reputation: 26280

First of all it's not quite clear what your intention is. If you just want to make sure that the licence can't be set simultaneously by two threads, you need something like this:

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

You notice that there is not 5 seconds timeout here. If you want to wait for 5 seconds and set the license regardless if the other thread has finished (basically what your code in the question does), instead of messing with mutex, you better do this (but I have a hard time understanding, why would you want this):

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

Using the Monitor object is more "native" approach than using mutex and it fits more here, since you don't need cross-process.

As far as Mutex go, it's a wrapper against system Mutex object surfaced to .NET. Named Mutexes are system-wide and visible across process. When you create a .NET Mutex object and supply a name, if the system Mutex with this name does not exist, it's created and wrapped into the .NET object that you get. If the system Mutex with this name was already created before, then this existing Mutex gets wrapped and returned as your new .NET Mutex object.

I don't think that you should use Mutexes in your scenario.

Upvotes: 2

Hand-E-Food
Hand-E-Food

Reputation: 12794

EDIT: I've since learned this answer is incorrect. zespri explains below.


There is no chance of mutex not being released because it is disposed as soon as the using block ends. Nothing else can ever see mutex because it's scoped to the method. Realise that you have two, independant Mutex objects here, one in Thread1 and one in Thread2. This is simply incorrect usage of Mutex.

If you need a Mutex, try this instead:

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

Changes:

  • Make mutex a class member so that all threads can see the same Mutex.

  • Check whether mutex was released, or whether it timed out.

  • Add a nested try/finally block to ensure mutex is released if setting the license throws an exception. The nesting is required because ReleaseMetux() can only be called by the thread that successfully called WaitOne().

Upvotes: -1

Related Questions