通过 Mutex/Semaphore 实现程序进程实例数量的控制
实现应用程序的进程单例或者特定数量的控制有多种方式,而通过信号量实现则是最简单有效的办法,在.NET中我们可以通过 Multex、Semaphore 类来实现。
1、Mutex、Semaphore 简介
- Mutex 是用于同步的线程或进程的互斥体。Multex 分为两种:未命名的局部互斥体和命名的系统互斥体。前者用于线程间的互斥,后者用于系统进程间的互斥。本文讨论的进程单例的实现将演示使用“命名的系统互斥体”。
- Semaphore 是用于同步的线程或进程的信号量。Semaphore 也分为两种:未命名的局部信号量和命名的系统信号量。前者用于线程间的同步,后者用于系统进程间的同步。本文的进程实例数量的控制的实现将演示使用“命名的系统信号量”。
2、进程单例的控制
实现思路:通过在程序启动后创建特定名称的命名的系统互斥体,标识应用程序的进程实例,后来启动的进程实例如果发现已经存在该名称的命名互斥体时,则直接退出进程,这样便保持了进程实例的唯一。
具体的代码如下:
进程单例控制
1 using System;
2 using System.Windows.Forms;
3 using System.Threading;
4
5 namespace DemoSingltonApplication
6 {
7 /// <summary>
8 /// 通过信号量互斥实现应用程序单例;
9 /// </summary>
10 static class Program
11 {
12 public const string APP_NAME = "My.SingltonApp.76E078632B58";
13
14 /// <summary>
15 /// 应用程序的主入口点。
16 /// </summary>
17 [STAThread]
18 static void Main()
19 {
20 Application.EnableVisualStyles();
21 Application.SetCompatibleTextRenderingDefault(false);
22
23 //通过 Mutex 实现程序单例;
24 bool isFirstAppInstance;
25
26 Mutex mutex = new Mutex(true, APP_NAME, out isFirstAppInstance);
27 if (isFirstAppInstance)
28 {
29 Application.Run(new FrmMain());
30 }
31 else
32 {
33 MessageBox.Show("系统中已经运行了程序的其它实例!", "注意", MessageBoxButtons.OK, MessageBoxIcon.Warning);
34 }
35 }
36 }
37 }
3、进程实例数量的控制
实现思路:在应用程序启动后创建特定名称的具有指定最大资源数的命名的系统信号量,并请求进入该信号量,如果无法进入该信号量,则表明系统中进程的实例已经达到最大数,此时退出,以此控制应用程序的进程实例不超过特定的数量。
具体代码如下:
进程实例数量的控制
using System;
using System.Windows.Forms;
using System.Threading;
namespace DemoSingltonApplication
{
/// <summary>
/// 通过信号量互斥实现应用程序单例;
/// </summary>
static class Program
{
public const string APP_NAME = "My.SingltonApp.76E078632B58";
public const int APP_INSTANCE_MAXCOUNT = 2;
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//通过 Semaphore 实现控制的程序的指定数量实例;
Semaphore sem = new Semaphore(APP_INSTANCE_MAXCOUNT, APP_INSTANCE_MAXCOUNT, APP_NAME);
bool isOverflow = !sem.WaitOne(0);
if (isOverflow)
{
MessageBox.Show("系统中运行的程序实例数已经超出允许的最大数量(" + APP_INSTANCE_MAXCOUNT + ")!", "注意", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
Application.Run(new FrmMain());
sem.Release();
}
}
}
}
总结:
1、常见的实现实例控制的方法还有通过 Process 类获取系统中的进程列表来控制实例数量,但是此方法存在潜在的风险,就是当把程序可执行文件名称改变后,运行的进程名称就改变了,此时控制失效。
2、通过 Mutex/Semaphore 实现程序进程实例的控制的关键在于互斥s体/信号量的名称的唯一性,如果使用的名称过于简单而容易冲突,导致不易察觉的异常。
因此推荐的命名方法是使用 GUID 命名。由于 GUID 是一个跟网卡MAC、计算机、时间、随机数相关的 128 位的随机整数,因此其在全球计算机中出现相同的概率非常小,因此通过指定一个特定的 GUID 字符串是安全,几乎可以肯定,一旦你创建了该GUID,就不会有另一个程序会拥有该GUID,除非人为地将此ID复制。
将示例中的 public const string APP_NAME = "My.SingltonApp.76E078632B58"; 改用为 GUID,并且将修饰符更改为 private ,就可以安全防止互斥体/信号量命名冲突的出现。


浙公网安备 33010602011771号