应用程序的两种单例控制: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);
}
}