释放在 WPF Application.OnStartUp() 中创建的命名互斥锁:哪个线程拥有它?

Posted

技术标签:

【中文标题】释放在 WPF Application.OnStartUp() 中创建的命名互斥锁:哪个线程拥有它?【英文标题】:Releasing a named mutex created in WPF Application.OnStartUp(): Which thread owns it? 【发布时间】:2015-12-08 17:40:06 【问题描述】:

我在 WPF 应用程序的 OnStartup 方法中创建了一个互斥锁。互斥锁不会在程序的其他任何地方使用,它的唯一目的是防止某些程序同时运行。应用程序关闭时如何释放此互斥锁?

根据documentation,必须从创建互斥锁的同一线程调用mutex.ReleaseMutex()。然而这会带来一个问题,因为我不控制调用OnStartup() 的线程。

假设我的OnStartup 方法如下所示:

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();
        
    

打电话releaseMutex()省钱吗...

在 OnExit() 方法中?protected override void OnExit()releaseMutex(); 在 ProcessExit 事件处理程序中?AppDomain.CurrentDomain.ProcessExit += (sender,e)=> releaseMutex(); 在终结器中?~App()releaseMutex(); 在未处理的异常事件处理程序中?AppDomain.CurrentDomain.UnhandledException += (sender,e)=> releaseMutex();

似乎 OnExit 方法最有可能在同一个线程中,但即便如此,这似乎也是一个粗略的假设。有没有办法忽略同线程的要求?或者我应该与我的互斥锁一起创建和存储一个单独的线程?

【问题讨论】:

只允许一个程序(或一组程序)的单个实例的通常方法是使用同步对象(通常是事件)的存在而不是状态来指示一个实例已经在运行。但这假设如果另一个实例正在运行,您将退出;如果您想等待实例退出然后继续,则不能使用该方法。从你的问题中我不清楚哪种情况适用。 【参考方案1】:

我个人根本不会费心发布它,尤其是因为你处理了AbandonedMutexException

如果互斥锁不用于同步同一进程的线程,则无需显式释放它。当进程终止时,操作系统会自动关闭进程创建的所有句柄,例如文件、套接字、互斥体、信号量和事件句柄。

如果您仍然喜欢发布它,请考虑使用 Application.OnExit(),因为它是从主线程调用的,就像 Startup() 一样。

【讨论】:

这样做的问题是,如果最初声明互斥锁的线程在进程退出之前退出,则同步失败。 @Harry Johnston 也许你是对的。这取决于互斥锁的使用方式(OP 代码中的“做事”部分)【参考方案2】:

根据我的研究,每个 GUI WPF 应用程序都有一个 UI 线程,可以通过Application.Current.Dispatcher 访问(例如参见this answer)。此 UI 线程应在应用程序的整个生命周期内始终保持活动状态。

您可以使用Dispatcher.CheckAccess 来查看您是否在UI 线程中运行,如果不是,您可以使用Dispatcher.Invoke 在UI 线程的上下文中执行操作。

description of Application.Run 意味着 Application.OnStartup 始终在 UI 线程上运行,但检查它应该不会有害,并且在必要时使用 UI 线程调度程序调用创建互斥锁的操作。

Application.OnExit 也总是在 UI 线程上运行似乎是一个合理的猜测,但由于这似乎没有记录在案,您应该检查并在必要时使用 UI 线程调度程序来调用释放的操作互斥体。

正如 Alexm 正确指出的那样,如果应用程序在自己的进程中运行(通常是这种情况),您实际上不需要显式释放互斥锁,但您确实需要确保互斥锁所在的线程created on 将保持活动状态,直到您准备好释放它。我相信使用 UI 线程是确保这一点的最简单方法。

【讨论】:

以上是关于释放在 WPF Application.OnStartUp() 中创建的命名互斥锁:哪个线程拥有它?的主要内容,如果未能解决你的问题,请参考以下文章

C# Interop - 释放在非托管代码中分配的内存

如何释放在我的 RPC 服务器中分配的内存?

如何释放在子对话框中创建的 CWin 对象以避免内存泄漏

如何在 C# 中释放在 C++ 中分配的内存

释放在另一个循环中调用的函数中的alloated内存

C - 如何释放在其节点中具有链表的链表?