咨询区

  • C. Dragon 76

在 .NET 中是否有比较好的方法可以阻止一个 application 被同时开启了多个实例?如果没有好的办法,那么只能退其次,给每个 application 配一些操作规范。

回答区

  • ImJustPondering

我总结有两种解法。

  1. 使用 Meutx。
[STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}

Application.Run(new Form1());
}
}

private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";

关于 ​​Mutex​​ 更多资料,可参考:http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx

  1. 使用 Process

可以迭代进程列表,判断是否已经存在该进程名即可,参考如下代码:


using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
}
  • Tono Nam

其实可以仿 linux 上生成进程文件的方式,所以要做的就是在程序启动后,在某一个文件中写入一个默认的 uniqueid 值,参考如下代码:

  public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();

// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId + ".process-lock";

// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);

try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);

// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
}
};
t.Start();

}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
}

点评区

这个需求本质上和防重复登录时一样的,大概三种吧:

  1. 机器内作用域:

Metux,Process 是一个好办法。

  1. 跨机器或局域网作用域:

生成 PID 文件是一个好办法。

  1. 局域网,广域网:

可用 redis,zookeeper 之类的全局锁机制。

经典回顾