Относительно метода WaitOne() типа Mutex

Я написал небольшой кусочек кода. что-то вроде ниже

    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 ответа

Прежде всего, не совсем понятно, каково ваше намерение. Если вы просто хотите убедиться, что лицензия не может быть установлена ​​одновременно двумя потоками, вам нужно что-то вроде этого:

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

Использование объекта "Монитор" является более "нативным" подходом, чем использование мьютекса, и здесь он подходит больше, поскольку вам не требуется перекрестная обработка.

Что касается Mutex, то это оболочка для системного объекта Mutex, всплывающего в.NET. Именованные мьютексы являются общесистемными и видимыми во всем процессе. При создании объекта.NET Mutex и предоставлении имени, если система Mutex с таким именем не существует, она создается и включается в полученный объект.NET. Если система Mutex с таким именем уже была создана ранее, то существующий Mutex будет упакован и возвращен как ваш новый объект.NET Mutex.

Я не думаю, что вы должны использовать мьютексы в вашем сценарии.

WaitOne сгенерирует исключение AbandondMutexException, если процесс, который его удерживал, завершится без его освобождения. Даже с блоком try/finally все равно возможно, если вы прекратите отладку в неправильном месте в Visual Studio или используете диспетчер задач, чтобы завершить процесс, поэтому вам следует обработать этот случай либо путем блокировки мьютекса, либо выхода из приложения. Обратите внимание, что вызов release также будет генерироваться, если блокировка не была получена из-за сгенерированного исключения.

РЕДАКТИРОВАТЬ: С тех пор я узнал, что этот ответ неверен. 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(),

Другие вопросы по тегам