1

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

svick
  • 236,525
  • 50
  • 385
  • 514
Nivedita
  • 11
  • 1
  • 3
  • I find it unusual that you are not checking the result of WaitOne.. do you care if it times out or gets interrupted? Otherwise, it looks to me that you are fine in this simple example. But if you are calling WaitOne with a timeout, it would seem that it would be prudent to check the result – Alan Feb 14 '13 at 05:52
  • It is never going to freeze in the WaitOne() call, your mutex completely doesn't work. Every thread creates its own mutex so there's nothing to stop it. A crash is likely when both threads allocate the same named mutex at the same time. You might as well remove the code. – Hans Passant Feb 14 '13 at 05:58
  • Thanks for the response. But I created named mutex for interprocess communication. – Nivedita Feb 14 '13 at 06:08
  • And yes i have concerns if the waitOne gets interrupted or stuck somewhere. I will put the code that checks the result of waitOne.. but here i m wondering that is there anything that puts the WaitOne in a loop that will never get released in case I am not using the Timeout with WaitOne method – Nivedita Feb 14 '13 at 06:09
  • @HansPassant what do you mean by "Every thread creates its own mutex so there's nothing to stop it. A crash is likely when both threads allocate the same named mutex at the same time"? – Andrew Savinykh Feb 15 '13 at 00:18
  • @HansPassant that isn't how named mutexs work... – Yaur Feb 15 '13 at 00:52
  • Can you explain the purpose of this code? Why two threads? Why do you need synchronize access to licenses and how do you want to synchronize it? – Andrew Savinykh Feb 15 '13 at 01:08

3 Answers3

2

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.

Andrew Savinykh
  • 25,351
  • 17
  • 103
  • 158
1

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.

Noctis
  • 11,507
  • 3
  • 43
  • 82
Yaur
  • 7,333
  • 1
  • 25
  • 36
-1

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

Community
  • 1
  • 1
Hand-E-Food
  • 12,368
  • 8
  • 45
  • 80
  • You need to make your `mutex` static too. Or pass in an instance of the class to your static `SetAsposeLicense` method and call it on `inst.mutex`. – Joshua Feb 14 '13 at 22:43
  • Thanks! I missed seeing the `static` keyword. – Hand-E-Food Feb 15 '13 at 00:00
  • Erm... quick sanity test, what do you think this code will print out? https://gist.github.com/AndrewSav/4957694 – Andrew Savinykh Feb 15 '13 at 00:32
  • 2
    Mutex class just wraps a system mutex object. They are not only visible across threads, but also (gasp!) across processes. When you create a Mutex object passing it a name of an already existing system mutex, you well get a new .NET mutex object but it will be wrapped against the same system mutex. Even if the systems mutex was created in a different thread or process. That's basically the idea behind these objects. I think all this talk about making it a class member is hugely misleading. This is not how they are supposed to work. – Andrew Savinykh Feb 15 '13 at 00:34
  • Thanks for that! I've just had a good read over the [MSDN documentation](http://msdn.microsoft.com/en-AU/library/system.threading.mutex.aspx) to confirm that. – Hand-E-Food Feb 15 '13 at 00:40