在C#应用开发中,限制程序只能同时运行一个实例是常见需求,比如桌面工具、后台服务类程序,重复启动可能会导致数据冲突、资源占用异常等问题。下面介绍几种主流的实现方案,开发者可以根据项目类型选择合适的实现方式。

方案一:使用Mutex互斥体实现
Mutex是操作系统提供的同步基元,可以用于跨进程的互斥控制,是实现单实例运行的经典方案,适用于所有类型的C#程序,包括控制台程序、WinForm程序、WPF程序。
实现步骤
- 在程序入口处创建一个指定名称的Mutex实例
- 判断Mutex是否已经被其他进程创建,如果已经被创建则说明程序已经在运行,直接退出当前实例
- 如果Mutex创建成功,说明当前是第一个实例,正常启动程序,程序退出时释放Mutex
代码示例
using System;
using System.Threading;
using System.Windows.Forms;
namespace SingleInstanceDemo
{
static class Program
{
// 定义互斥体名称,建议使用唯一的GUID作为名称,避免和其他程序的互斥体冲突
private static Mutex singleInstanceMutex = null;
private const string MutexName = "Global\SingleInstanceDemo_8F2D4A3B-1C7E-4F9A-8B2D-3E6C5A7F9D1E";
[STAThread]
static void Main()
{
bool isNewInstance = false;
try
{
// 尝试创建互斥体,isNewInstance为true表示当前是第一个实例
singleInstanceMutex = new Mutex(true, MutexName, out isNewInstance);
if (!isNewInstance)
{
// 互斥体已存在,说明程序已经在运行,弹出提示后退出
MessageBox.Show("程序已经在运行中,请勿重复启动。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 以下为正常启动程序的代码
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
catch (Exception ex)
{
MessageBox.Show($"程序启动异常:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
// 程序退出时释放互斥体,注意只有创建互斥体的实例才能释放
if (singleInstanceMutex != null && isNewInstance)
{
singleInstanceMutex.ReleaseMutex();
singleInstanceMutex.Close();
}
}
}
}
}
使用Mutex方案时,互斥体名称前面的Global\前缀表示创建全局互斥体,这样即使是不同用户会话下的进程也能检测到,适合需要跨用户限制单实例的场景。如果不需要跨用户,可以去掉这个前缀,仅对当前用户会话生效。
方案二:通过检测进程实现
该方案通过遍历当前系统运行的进程,判断是否存在和当前程序同名的进程,如果存在则说明程序已经在运行。实现简单,不需要依赖额外的同步基元,但存在一定局限性,比如如果程序改名后运行就无法检测到,且进程名可能存在重复的情况。
代码示例
using System;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
namespace SingleInstanceDemo
{
static class Program
{
[STAThread]
static void Main()
{
// 获取当前进程的进程名
string currentProcessName = Process.GetCurrentProcess().ProcessName;
// 获取所有同名进程
Process[] processes = Process.GetProcessesByName(currentProcessName);
// 如果同名进程数量大于1,说明程序已经在运行(当前进程本身算一个)
if (processes.Length > 1)
{
MessageBox.Show("程序已经在运行中,请勿重复启动。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 正常启动程序
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
这种方案的优势是实现简单,不需要处理互斥体的释放逻辑,但缺点也比较明显:如果程序被复制后修改了文件名,进程名会发生变化,就无法检测到重复实例;如果系统中有其他同名进程,也会出现误判。因此该方案仅适合对单实例要求不高的简单场景。
方案三:使用WindowsFormsApplicationBase实现(WinForm专属)
如果是WinForm程序,可以使用Microsoft.VisualBasic命名空间下的WindowsFormsApplicationBase类来实现单实例运行,该类内置了单实例运行的支持,还可以实现启动第二个实例时激活已运行的实例窗口,功能更加完善。
实现步骤
- 首先需要在项目中引用
Microsoft.VisualBasic程序集 - 创建一个继承
WindowsFormsApplicationBase的类,配置单实例属性 - 重写
OnStartupNextInstance方法,处理后续启动实例的逻辑,比如激活主窗口 - 在程序入口使用该自定义应用程序类启动程序
代码示例
using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;
namespace SingleInstanceDemo
{
// 自定义应用程序基类,继承WindowsFormsApplicationBase
class SingleInstanceApp : WindowsFormsApplicationBase
{
public SingleInstanceApp()
{
// 设置为单实例应用
this.IsSingleInstance = true;
// 设置主窗口
this.MainForm = new MainForm();
}
// 当启动下一个实例时触发,比如用户再次双击程序图标启动
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
base.OnStartupNextInstance(eventArgs);
// 激活已运行的主窗口
if (this.MainForm != null)
{
if (this.MainForm.WindowState == FormWindowState.Minimized)
{
this.MainForm.WindowState = FormWindowState.Normal;
}
this.MainForm.Activate();
this.MainForm.BringToFront();
}
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// 使用自定义的单实例应用类启动程序
SingleInstanceApp app = new SingleInstanceApp();
app.Run(Environment.GetCommandLineArgs());
}
}
}
这种方案的优点是功能完善,不仅限制单实例,还能在用户重复启动程序时自动激活已运行的窗口,提升用户体验,缺点是仅适用于WinForm程序,且需要引用VisualBasic相关的程序集。
不同方案对比
为了帮助开发者选择合适的方案,下面从适用场景、优缺点等方面对不同方案进行对比:
| 实现方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Mutex互斥体方案 | 所有C#程序(控制台、WinForm、WPF等) | 通用性强,跨进程、跨用户会话支持,可靠性高 | 需要处理互斥体的创建和释放逻辑 |
| 进程检测方案 | 简单的单实例需求场景 | 实现简单,无需额外依赖 | 容易误判,程序改名后失效 |
| WindowsFormsApplicationBase方案 | WinForm程序 | 内置单实例支持,可自动激活已运行窗口,用户体验好 | 仅适用于WinForm,需要引用VisualBasic程序集 |
开发者可以根据项目的实际需求选择对应的实现方案,大多数场景下推荐使用Mutex互斥体方案,通用性和可靠性都更有保障。
C#单实例运行MutexProcessWindowsFormsApplicationBase修改时间:2026-07-13 01:54:35