Automatic Semaphore release on process Exit

前端 未结 3 575
一整个雨季
一整个雨季 2021-01-01 02:16

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

相关标签:
3条回答
  • 2021-01-01 02:28

    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.

    0 讨论(0)
  • 2021-01-01 02:34

    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.
    0 讨论(0)
  • 2021-01-01 02:43

    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."

    0 讨论(0)
提交回复
热议问题