Получить исключение при получении мьютекса после перезапуска службы - PullRequest
0 голосов
/ 06 июля 2018

Я пишу службу Windows с помощью C #. Он непрерывно читает из MSMQ, вызывая Read() из потока:

public string Read()
    {
        try
        {
            if (!readMutex.WaitOne(100))
            {
                return null;
            }
            var message = queue.Receive();
            return (string)message.Body;
        }
        catch (Exception ex)
        {
            logger.Error("Exception:" + ex);
        }
        finally
        {
            readMutex.ReleaseMutex();
        }

        return null;
    }

Мьютекс создается в конструкторе класса и располагается в деструкторе.

Проблема в том, что после остановки и перезапуска службы я всегда получаю AbandonedMutexException в if (!readMutex.WaitOne(100)) при первом вызове Read().

После подключения отладчика и добавления точек останова я обнаружил, что при остановке службы блок finally никогда не вводится, я не уверен, что это будет проблемой.

Возможно, это не большая проблема, потому что при следующем вызове Read() исключение больше не возникает. Но мне интересно, есть ли простой способ решить эту проблему?

Добавить 1 : Я обнаружил, что деструктор всегда вызывается при остановке службы, поэтому я попытался освободить мьютекс в деструкторе. Но обнаружил, что мне не разрешено его выпускать, потому что мьютекс, кажется, получен в другом контексте потока.

Добавить 2 : Для тех, кто интересуется этим вопросом, я добавлю то, что нашел после изучения происходящего.

Я проверил, что если я создаю программу, которая получает мьютекс без его освобождения, а затем закрывает программу, то при следующем запуске программы она все равно может успешно получить мьютекс без каких-либо исключений. Это противоречит симптому этой проблемы, а также противоречит тому, что я привык думать.

Я думаю, что правда в том, что ОС закрывает мьютекс для меня при выходе из программы, поэтому в следующий раз я смогу его получить.

Но почему я не справился с этим сервисом? Наконец, я обнаружил, что у меня есть еще один второй сервис, который также создал мьютекс этого пути. Этот второй сервис просто держал дескриптор мьютекса, ничего не делая с ним (например, ожидая его). В этом случае, когда мой первый сервис перезапускается и снова пытается получить Mutex, он получает исключение.

В заключение, когда программа завершается с невыпущенным мьютексом: 1) если на мьютекс также ссылаются какие-либо другие службы / приложения, то при следующем получении мьютекса будет сгенерировано исключение. 2) если это единственная программа, ссылающаяся на этот мьютекс, то операционная система обработает это изящно для меня, и при следующем получении не будет сообщено об ошибке.

1 Ответ

0 голосов
/ 06 июля 2018

readMutex.ReleaseMutex();, скорее всего, никогда не вызывается, когда служба отключается

Более того, Receive блокируется до тех пор, пока не получит сообщение, поэтому вполне вероятно, что, когда служба завершает работу, время истекает, она думает, что она зависла, и завершает процесс, не завершая корректно.

Здесь есть несколько подходов,

Возможно, вам лучше позвонить MessageQueue.Receive Method (TimeSpan) с коротким тайм-аутом и соответствующим образом скорректировать свою логику, таким образом (при выключении) прием, как мы надеемся, истечет до истечения времени ожидания обслуживания.

Другой подход - запустить это в потоке или задаче, убить его при завершении работы и убедиться, что вы вызываете readMutex.ReleaseMutex()

В любом случае, у вас сейчас достаточно информации, и вы сможете решить ее так, как вам удобно

...