我正在使用Semaphore来限制应用程序可以运行的并发实例数。
流程可以通过多种方式终止。可以创建Semaphore
,以便在进程退出时自动释放吗?
编辑:
我想要一些魔法来自动清除信号量“提升”状态,以便在退出或崩溃时拥有它。只是为了确保它被清除,无论如何。
MORE:
我正在寻找任何可行的选择,考虑:
答案 0 :(得分:6)
您可以挂钩AppDomain.ProcessExit
事件来执行任何清除操作,例如释放信号量。
通常,命名信号量旨在协调跨进程的资源,而不考虑特定的进程生命周期。 .NET中的信号量由native Windows semaphore objects支持,MSDN说:
信号量对象在其最后一个句柄关闭时被销毁。关闭句柄不会影响信号量计数;因此,请务必在关闭句柄之前或进程终止之前调用ReleaseSemaphore。
因此,正确的方法是在流程终止之前进行明确处理。
更新 - 需要考虑的其他选项:
AppDomain.ProcessExit
事件中手动处理“紧急”释放是不可行的,请考虑创建一个IDisposable
包装器,它将在其构造函数中获取信号量并在{{1}中释放它} 方法。 更新 - 如果应用程序崩溃或强制终止(即通过任务管理器),Dispose
将无法处理。因此,可能无法正确地最终确定/处理/处理在多个进程之间共享的任何非托管资源。有关详细信息,请参阅this article。
可行的选择可能是creating a named pipe。命名管道的优点是,一旦创建过程终止,它们就会停止退出。根据MSDN:
请注意,命名管道的实例可能有多个与之关联的句柄。当命名管道实例的最后一个句柄关闭时,总是删除命名管道的实例。
有两个选项可以限制管道实例的数量:
ProcessExit
参数中指定FILE_FLAG_FIRST_PIPE_INSTANCE
标志,可以禁止创建多个管道实例。然后,尝试创建管道的第二个进程将收到错误。dwOpenMode
参数中允许的实例数。如果允许nMaxInstances
,N
进程将收到错误。答案 1 :(得分:4)
适当的答案是在您的信号量周围实施“关键终结器”,以确保在所有情况下进行适当的清理。 ProcessExit不保证在故障情况下执行,例如由于不可捕获的异常导致强制appdomain卸载(StackOverflowException和InvalidProgramException是两个很好的例子。)
更多信息@ http://msdn.microsoft.com/en-us/library/system.runtime.constrainedexecution.criticalfinalizerobject.aspx, 引用:“公共语言运行时(CLR)保证所有关键的终结代码都有机会执行,前提是终结器遵循CER的规则,即使在CLR强行卸载应用程序域或中止线程的情况下也是如此。“
答案 2 :(得分:1)
如果与Daniel不同,您可以升级到.Net 3.5,可以使用NamedPipeServerStream课程来创建pipe。
NamedPipeServerStream pipe;
try
{
pipe = new NamedPipeServerStream(name, PipeDirection.InOut, 3);
}
catch (IOException)
{
//Maximum number of instances reached (3).
}
我建议您在管道上保留静态引用,以避免在退出流程之前完成。 管道的缺点是你不能等到没有轮询的实例可用。