使用c# mutex,可以做到跨进程同步,实现应用程序只能单开,不能多开,参考:
单开.NET Core控制台项目,示例代码:
using System; using System.Threading; namespace NetCoreMutex { class Program { private static Mutex mutex = null; //设为Static成员,是为了在整个程序生命周期内持有Mutex static void Main() { bool firstInstance; mutex = new Mutex(true, @"GlobalMutexSampleApp", out firstInstance); try { if (!firstInstance) { Console.WriteLine("已有实例运行,输入回车退出……"); Console.ReadLine(); return; } else { Console.WriteLine("我们是第一个实例!"); for (int i = 60; i > 0; --i) { Console.WriteLine(i); Thread.Sleep(1000); } } } finally { //只有第一个实例获得控制权,因此只有在这种情况下才需要ReleaseMutex,否则会引发异常。 if (firstInstance) { mutex.ReleaseMutex(); } mutex.Close(); mutex = null; } } } }
使用Mutex需要注意的两个细节:
- 可能你已经注意到了,例子中在给Mutex命名的字符串里给出了一个“Global”的前缀。这是因为在运行终端服务(或者远程桌面)的服务器上,已命名的全局 mutex 有两种可见性。如果名称以前缀“Global”开头,则 mutex 在所有终端服务器会话中均为可见。如果名称以前缀“Local”开头,则 mutex 仅在创建它的终端服务器会话中可见,在这种情况下,服务器上各个其他终端服务器会话中都可以拥有一个名称相同的独立 mutex。如果创建已命名 mutex 时不指定前缀,则它将采用前缀“Local”。在终端服务器会话中,只是名称前缀不同的两个 mutex 是独立的 mutex,这两个 mutex 对于终端服务器会话中的所有进程均为可见。即:前缀名称“Global”和“Local”仅用来说明 mutex 名称相对于终端服务器会话(而并非相对于进程)的范围。最后需要注意“Global”和“Local”是大小写敏感的。
- 既然父类实现了IDisposalble接口,那么说明这个类一定需要你手工释放那些非托管的资源。所以必须使用try/finally,亦或我讨厌的using,调用Close()方法来释放Mutex所占用的所有资源!