进程退出时自动释放信号量

发布于 2024-10-20 17:16:52 字数 375 浏览 1 评论 0原文

我正在使用信号量来限制我的应用程序可以运行的并发实例的数量。

进程终止的方式有很多种。是否可以创建信号量以便在进程退出时自动释放?

编辑:

我想要一些魔法来自动清理退出或崩溃时拥有信号量的进程的“引发”状态。无论如何,只是为了确保它被清除。

更多:

我正在寻找任何可行的选择,考虑到:

  • 如果不需要外部应用程序来获取受保护应用程序的每个实例,那就太好了,
  • 它不必是信号量 - 任何具有 COUNTER 的同步对象并且在所有者进程死亡时自动释放会很好,即使它是作弊的
  • 我正在使用.NET 2.0,无法移动到该项目的较新版本,但可以使用 c/c++ 和互操作来利用某些东西,如果有东西

I am using Semaphore to limit the number of concurrent instances my application can run.

There are many ways a process can terminate. Can the Semaphore be created so it automatically releases upon process exit?

EDIT:

I would like some magic to automatically clean up the semaphore 'raised' state for the process owning it upon exit or crash. Just to be sure that it is cleared, no matter what.

MORE:

I am looking for any viable option for it, considering:

  • it would be great that NO external application is required to get a hold on every instance of the protected application
  • it doesn't have to be Semaphore - any synchronization object that has COUNTER and is AUTOMATICALLY released upon death of a owner process will be fine, even if it's cheating
  • I am using .NET 2.0, can't move to newer version on this project, but can use c/c++ and inter-op to leverage something if there is something

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

在你怀里撒娇 2024-10-27 17:16:52

您可以挂钩 AppDomain.ProcessExit 事件来执行任何清理操作,例如释放信号量。

一般来说,命名信号量旨在协调跨进程的资源,而不考虑特定的进程生命周期。 .NET 中的信号量由本机 Windows 信号量对象支持,MSDN 说:

信号量对象在其最后一个句柄关闭时被销毁。关闭句柄不会影响信号量计数;因此,请务必在关闭句柄之前或进程终止之前调用 ReleaseSemaphore。

因此,正确的方法是在进程终止之前进行显式处理。


更新 - 要考虑的其他选项:

  1. 如果在 AppDomain.ProcessExit 事件中手动处理“紧急”释放不可行,请考虑创建一个 IDisposable 包装器将在其构造函数中获取信号量并在 Dispose 方法中释放它。
  2. 另一个问题是:信号量是这种情况下正确的同步对象吗?一个简单的(命名的)互斥体不是更好吗?

更新 - 如果应用程序崩溃或强制终止(即通过任务管理器),ProcessExit 将没有机会得到处理。因此,多个进程之间共享的任何非托管资源可能无法正确完成/处置/处理。请参阅本文了解更多信息细节。

一个可行的选择可能是创建一个命名管道。命名管道的优点是一旦创建进程终止它们就停止退出。根据 MSDN:

请注意,命名管道的一个实例可能有多个与其关联的句柄。当命名管道实例的最后一个句柄关闭时,命名管道的实例始终会被删除。

有两个选项可以限制管道实例的数量:

  1. 仅一个实例:通过在 dwOpenMode 参数中指定 FILE_FLAG_FIRST_PIPE_INSTANCE 标志,可以禁止创建管道的多个实例。管道。然后,尝试创建管道的第二个进程将收到错误。
  2. 更多实例:通过在 nMaxInstances 参数中指定允许的实例数。当允许N时,第N+1进程将收到错误。

You can hook into the AppDomain.ProcessExit event to perform any cleanup operations like releasing the semaphore.

Generally, named semaphores are designed to coordinate resources across processes without taking particular process life-time into account. Semaphores in .NET are backed by native Windows semaphore objects, and the MSDN says:

The semaphore object is destroyed when its last handle has been closed. Closing the handle does not affect the semaphore count; therefore, be sure to call ReleaseSemaphore before closing the handle or before the process terminates.

Hence the right approach is explicit handling before process termination.


Update — Other options to consider:

  1. In case it's not feasible to handle “emergency” release manually in the AppDomain.ProcessExit event, consider creating an IDisposable wrapper that would acquire the semaphore in its constructor and release it in the Dispose method.
  2. Another question is: is a Semaphore the right synchronization object for this case? Wouldn't a simple (named) mutex work better?

Update — In case of an application crash or forced termination (i.e. via Task Manager) ProcessExit won't have a chance to be handled. Hence any unmanaged resources shared between multiple processes may not be finalized / disposed / handled correctly. See this article for further details.

A viable option may be creating a named pipe. The advantage of named pipes is they cease to exit once the creating process is terminated. According to MSDN:

Note that an instance of a named pipe may have more than one handle associated with it. An instance of a named pipe is always deleted when the last handle to the instance of the named pipe is closed.

There are two options to limit the number of pipe instances:

  1. Just one instance: By specifying the FILE_FLAG_FIRST_PIPE_INSTANCE flag in the dwOpenMode argument it is possible to prohibit creation of multiple instances of the pipe. Then, the second process attempting to create the pipe will receive an error.
  2. More instances: By specifying the number of allowed instances in the nMaxInstances argument. When N are allowed, the N+1st process will receive an error.
掐死时间 2024-10-27 17:16:52

适当的答案是在信号量周围实现“关键终结器”,以确保在所有情况下都能进行适当的清理。 ProcessExit 不保证在失败情况下执行,例如由于不可捕获的异常而强制卸载应用程序域(StackOverflowException 和 InvalidProgramException 是两个很好的例子。)

更多信息@ http://msdn.microsoft.com/en-us/library/system.runtime.constrainedexecution.riticalfinalizerobject.aspx,
引用:“公共语言运行时 (CLR) 保证所有关键的终结代码都有机会执行,前提是终结器遵循 CER 规则,即使在 CLR 强制卸载应用程序域或中止线程的情况下也是如此。 ”。

The appropriate answer is to implement a 'Critical Finalizer' around your semaphore to ensure proper clean-up in all cases. ProcessExit is not guaranteed to execute in a failure scenario, such as a forced appdomain unload due to non-trappable exceptions (StackOverflowException and InvalidProgramException being two good examples.)

More info @ http://msdn.microsoft.com/en-us/library/system.runtime.constrainedexecution.criticalfinalizerobject.aspx,
to quote: "the common language runtime (CLR) guarantees that all critical finalization code will be given the opportunity to execute, provided the finalizer follows the rules for a CER, even in situations where the CLR forcibly unloads an application domain or aborts a thread."

ぽ尐不点ル 2024-10-27 17:16:52

如果与 Daniel 不同,您可以将 NamedPipeServerStream 升级到 .Net 3.5 a> 类可用于创建您的管道

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

我建议您在管道上保留静态引用,以避免退出进程之前完成。
管道的缺点是您不能等到实例可用而不进行轮询。

If, unlike Daniel, you can upgrade to .Net 3.5 a NamedPipeServerStream class is available to create your pipe.

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

I advice you to keep a static reference on the pipe to avoid Finalization before exiting the process.
The drawback of pipe is that you can't wait until an instance is available without polling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文