一、应用程序互斥锁
说明:测试反馈打包生成的程序,多次双击后运行多次,于是增加了单实例限制。
举个例子,我拿了唯一的钥匙打开了门,然后把钥匙带进去了,别人不能进,等我出去了关好门还要把钥匙还回去。
同理,通过静态构造函数static,在程序启动的那一刻,构造一个Mutex(互斥对象,系统级别的锁,跨进程可见),加上 typeof(App).GUID.ToString(),绑定唯一性标识 ,这样再次启动同一个程序的时候因为当前Mutex已经存在就直接退出。
关闭程序时需要释放当前Mutex
csharp
public partial class App : Application
{
private static readonly Mutex _mutex;
private static bool _isSingleInstance;
static App()
{
// 单实例检查
string mutexName = "SIMWPF_SingleInstance_Mutex_" + typeof(App).GUID.ToString();
_mutex = new Mutex(true, mutexName, out _isSingleInstance);
if (!_isSingleInstance)
{
Environment.Exit(0);//立即终止进程,参数0标识正常退出,绕过清理不执行后续代码
return;
}
}
private void App_Startup(object sender, StartupEventArgs e) //Application_Startup
{
// ... 原有代码 ...
this.Exit += App_Exit;
}
private void App_Exit(object sender, ExitEventArgs e)
{
// 释放
_mutex?.ReleaseMutex();
_mutex?.Dispose(); //释放非托管资源(系统资源)
}
}
附:
二、WPF应用程序的生命周期

三、 程序退出方法对比
| 方法 | 说明 | 适用场景 |
|---|---|---|
Environment.Exit(0) |
立即终止进程 | 静态构造函数等早期退出 |
Application.Current.Shutdown() |
WPF 优雅退出 | 正常关闭程序 |
this.Close() |
关闭窗口 | 关闭单个窗口 |
四、 其他
- lock是进程内的,无法跨进程检测,Mutex是系统级别的
- 静态构造函数是最早阶段执行的,确保单例检查在所有初始化之前完成
- 内核对象是由操作系统内核管理的资源,句柄是进程访问内核对象的"指针",引用计数是记录有多少句柄指向该对象
- 程序崩溃,操作系统会自动回收崩溃的进程内核对象(Mutex(互斥量)、Event(时间))、Semaphore(信号量)、File Handle(文件句柄)、Registry Key(注册表句柄)、Thread(线程)、Process(进程句柄)等)