问题
I create a mutex within the OnStartup
Method of a WPF app. The mutex is not used anywhere else in the program, its only purpose is to prevent certain programs from running concurrently. How can I release this mutex when the application closes?
According to the documentation, mutex.ReleaseMutex()
must be called from the same thread that created the mutex. However this presents a problem, since I do not control the thread that calls OnStartup()
.
Suppose my OnStartup
method looks like this:
public partial class App : Application
{
private Mutex mutex;
private bool hasHandle = false;
protected override void OnStartup(StartupEventArgs e)
{
bool createdNew;
mutex = new Mutex(false, @"Global\XYZ", out createdNew);
try
{
hasHandle = mutex.WaitOne(5000, false);
if (!hasHandle)
{/*do stuff*/};
}
catch (AbandonedMutexException)
{
hasHandle = true;
// do stuff
}
base.OnStartup(e);
}
private void releaseMutex()
{
if (mutex!=null)
{
if (hasHandle) mutex.ReleaseMutex();
mutex.Dispose();
}
}
}
Is it save to call releaseMutex()
...
- in the OnExit() method?
protected override void OnExit(){releaseMutex();}
- in the ProcessExit event handler?
AppDomain.CurrentDomain.ProcessExit += (sender,e)=> releaseMutex();
- in a finalizer?
~App(){releaseMutex();}
- in the unhandled exception event handler?
AppDomain.CurrentDomain.UnhandledException += (sender,e)=> releaseMutex();
It seems like the OnExit method has the best chance to be in the same thread, but even that seems a sketchy assumption. Is there a way to ignore the same-thread requirement? Or should I create and store a separate thread in conjunction with my mutex?
回答1:
I personally wouldn't bother releasing it at all, especially since you handle AbandonedMutexException
.
If a mutex is not used to synchronize threads of the same process there is no need to explicitly release it. When a process terminates OS automatically closes all handles created by the process, such as files, sockets, mutexes, semaphores and event handles .
If you still prefer to release it consider using Application.OnExit()
since it is called from the main thread, just like the Startup()
.
回答2:
According to my research, every GUI WPF application has a UI thread which can be accessed via Application.Current.Dispatcher
(see for example this answer). This UI thread should always remain active for the lifetime of the application.
You can use Dispatcher.CheckAccess
to see whether you are running in the UI thread, and if you are not you can use Dispatcher.Invoke
to execute an action in the context of the UI thread.
The description of Application.Run implies that Application.OnStartup
is always run on the UI thread, but it should not be harmful to check and, if necessary, use the UI thread dispatcher to invoke the action that creates the mutex.
It seems a reasonable guess that Application.OnExit
is also always run on the UI thread, but since this does not appear to be documented, you should check and, if necessary, use the UI thread dispatcher to invoke the action that releases the mutex.
As Alexm correctly points out, you do not in fact need to explicitly release the mutex provided that the application is running in its own process (which will usually be the case) but you do need to ensure that the thread the mutex is created on will remain active until you are ready to free it. I believe using the UI thread is the simplest way to ensure this.
来源:https://stackoverflow.com/questions/32535686/releasing-a-named-mutex-created-in-wpf-application-onstartup-which-thread-own