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:
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:
AppDomain.ProcessExit
event, consider creating an IDisposable
wrapper that would acquire the semaphore in its constructor and release it in the Dispose
method. 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:
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.nMaxInstances
argument. When N
are allowed, the N+1
st process will receive an error.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."
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With