应用程序的两种单例控制详解
应用程序的两种单例控制:1 关闭上一个进程,开启新的进程;2 保持上一个进程,阻止当前新开的进程
上述第一种:采用EventWaitHandle 实现了保持单例应用的功能,并且通过 EventWaitHandleSecurity 类型设置了信号量的访问权限,保证了多个进程之间的安全性
/// <summary> /// EventWaitHandle 实现了保持单例应用的功能,并且通过 EventWaitHandleSecurity 类型设置了信号量的访问权限,保证了多个进程之间的安全性 /// </summary> class Program { private static void Main(string[] args) { _currentProcessId = Process.GetCurrentProcess().Id; SingletonApplication("Service"); ProcessWait(); } /// <summary> /// 保持单例应用 /// </summary> /// <param name="appName"></param> private static void SingletonApplication(string appName) { string name = $"{Identification}" + appName; try { var security = SetEventWaitHandleSecurity(); // name 以及createdNew 是关键,其中initialState 初始为false,WaitOne将等待到信号量set通过 _singleWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset, name, out bool createdNew, security); if (createdNew) return; DisposeOldSemaphore(name); _singleWaitHandle = CreateNewSemaphore(name, false, security); _singleWaitHandle.Reset(); } catch (Exception arg) { Console.WriteLine($"保持单例出现异常:{arg}"); } } /// <summary> /// 保证了多个进程之间的安全性 /// </summary> /// <returns></returns> private static EventWaitHandleSecurity SetEventWaitHandleSecurity() { EventWaitHandleAccessRule rule = new EventWaitHandleAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), EventWaitHandleRights.FullControl, AccessControlType.Allow); EventWaitHandleSecurity eventWaitHandleSecurity = new EventWaitHandleSecurity(); eventWaitHandleSecurity.AddAccessRule(rule); return eventWaitHandleSecurity; } /// <summary> /// 释放旧的信号 /// </summary> /// <param name="name"></param> private static void DisposeOldSemaphore(string name) { Console.WriteLine($"{_currentProcessId}:已经有一个进程在运行了,开始让上一个应用的信号量通过,然后等到上一个应用所持有的信号量退出之后,启动自己的信号量"); _singleWaitHandle.Set(); _singleWaitHandle.Dispose(); while (EventWaitHandle.TryOpenExisting(name, out var handle)) handle?.Dispose(); } /// <summary> /// 创建新的信号量 /// </summary> /// <param name="name"></param> /// <param name="createdNew"></param> /// <param name="security"></param> /// <returns></returns> private static EventWaitHandle CreateNewSemaphore(string name, bool createdNew, EventWaitHandleSecurity security) { Console.WriteLine($"{_currentProcessId}:开始创建属于自己的信号量"); return new EventWaitHandle(initialState: false, EventResetMode.ManualReset, name, out createdNew, security); } /// <summary> /// 进程等待 /// </summary> private static void ProcessWait() { Console.WriteLine($"{_currentProcessId}:信号量开始堵塞主线程"); _singleWaitHandle.WaitOne(); Console.WriteLine($"{_currentProcessId}:信号量收到通过信号,并开始Dispose信号量"); _singleWaitHandle.Dispose(); Console.WriteLine($"{_currentProcessId}:进程退出"); } private const string Identification = "SingletonApp"; private static EventWaitHandle _singleWaitHandle; private static int _currentProcessId; }
上述第二种:比较简单采用Mutex
/// <summary> /// App.xaml 的交互逻辑 /// </summary> public partial class App { private static System.Threading.Mutex mutex; protected override void OnStartup(StartupEventArgs e) { //程序启动判断是否重复启动 mutex = new System.Threading.Mutex(true, Assembly.GetExecutingAssembly().GetName().Name); if (!mutex.WaitOne(0, false)) { System.Environment.Exit(0); return; } base.OnStartup(e); } }