C#如何实现程序单实例运行

来源:Nodejs社区作者:缅甸程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《C#如何实现程序单实例运行》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何实现程序单实例运行》有用,将其分享出去将是对创作者最好的鼓励。

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

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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。