Я пишу службу 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) если это единственная программа, ссылающаяся на этот мьютекс, то операционная система обработает это изящно для меня, и при следующем получении не будет сообщено об ошибке.