Автоматическое освобождение семафора при выходе из процесса - PullRequest
4 голосов
/ 08 марта 2011

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

Есть много способов, которыми процесс может завершиться.Можно ли создать Semaphore, чтобы он автоматически высвобождался при выходе из процесса?

РЕДАКТИРОВАТЬ:

Я бы хотел, чтобы какая-то магия автоматически очищала поднятое состояние семафора для процесса, владеющего имвыход или сбой.Просто чтобы быть уверенным, что он очищен, несмотря ни на что.

БОЛЬШЕ:

Я ищу любой приемлемый вариант для него, учитывая:

  • это будетзамечательно, что НИКАКОЕ внешнее приложение не требуется для удержания каждого экземпляра защищенного приложения
  • это не обязательно должен быть семафор - любой объект синхронизации, который имеет СЧЕТЧИК и АВТОМАТИЧЕСКИ освобождается после смерти процесса владельцавсе будет хорошо, даже если это обманывает
  • Я использую .NET 2.0, не могу перейти на более новую версию в этом проекте, но могу использовать c / c ++ и взаимодействие, чтобы использовать что-то, если есть что-то

Ответы [ 3 ]

6 голосов
/ 08 марта 2011

Вы можете подключиться к событию AppDomain.ProcessExit для выполнения любых операций очистки, таких как освобождение семафора.

Как правило, именованные семафоры предназначены для координации ресурсов между процессами без учета конкретного времени жизни процесса. Семафоры в .NET поддерживаются собственными объектами семафора Windows , а MSDN говорит:

Объект семафора уничтожается, когда его последний дескриптор был закрыт. Закрытие дескриптора не влияет на количество семафоров; поэтому обязательно вызовите ReleaseSemaphore перед закрытием дескриптора или перед завершением процесса.

Следовательно, правильный подход - явная обработка перед завершением процесса.


Обновление - Другие варианты для рассмотрения:

  1. В случае, если не представляется возможным обработать «аварийное» освобождение вручную в событии AppDomain.ProcessExit, рассмотрите возможность создания оболочки IDisposable, которая получит семафор в своем конструкторе и освободит его методом Dispose.
  2. Другой вопрос: является ли семафор подходящим объектом синхронизации для этого случая? Разве простой (именованный) мьютекс не будет работать лучше?

Обновление - В случае сбоя приложения или принудительного завершения (т. Е. Через диспетчер задач) ProcessExit не будет иметь шансов быть обработанным. Следовательно, любые неуправляемые ресурсы, совместно используемые несколькими процессами, могут быть неправильно завершены / удалены / обработаны. Подробнее см. в этой статье .

Возможным вариантом может быть , создающий именованный канал . Преимущество именованных каналов в том, что они перестают выходить после завершения процесса создания. По данным MSDN:

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

Существует два варианта ограничения количества экземпляров канала:

  1. Всего один экземпляр: указав флаг FILE_FLAG_FIRST_PIPE_INSTANCE в аргументе dwOpenMode, можно запретить создание нескольких экземпляров канала. Затем второй процесс, пытающийся создать канал, получит ошибку.
  2. Больше экземпляров: указав количество разрешенных экземпляров в аргументе nMaxInstances. Если разрешено N, процесс N+1 будет получать ошибку.
4 голосов
/ 06 декабря 2011

Правильный ответ - внедрить «Критический финализатор» вокруг вашего семафора, чтобы обеспечить надлежащую очистку во всех случаях.Не гарантируется выполнение ProcessExit в сценарии сбоя, например, принудительной выгрузке домена приложения из-за исключений, которые нельзя отследить (StackOverflowException и InvalidProgramException являются двумя хорошими примерами).: «общеязыковая среда выполнения (CLR) гарантирует, что весь критический код завершения будет предоставлена ​​возможность выполнения при условии, что финализатор следует правилам для CER, даже в ситуациях, когда CLR принудительно выгружает домен приложения или прерывает поток»

1 голос
/ 26 июля 2012

Если, в отличие от Даниэля, вы можете обновить до .Net 3.5 a NamedPipeServerStream класс доступен для создания вашей трубы .

  NamedPipeServerStream pipe;
  try
  {
    pipe = new NamedPipeServerStream(name, PipeDirection.InOut, 3);
  }
  catch (IOException)
  {
    //Maximum number of instances reached (3).
  }

Я советую вамсохраняйте статическую ссылку на канал, чтобы избежать финализации перед выходом из процесса.Недостаток канала заключается в том, что вы не можете ждать, пока экземпляр не станет доступен без опроса.

...