怎么让C#程序同时只能运行一个实例

时间:2022-06-19 17:46:04

双击一个WinForm程序,会打开一个界面,也即运行了一个程序的实例;双击多次的时候,会出现多个程序界面。有时候我们需要只允许程序只能同时运行一个实例。实现方式有很多。

一.   进程互斥

原理:通过获取系统进程列表,如果发现有重名的,则表示程序已经运行了,此时新运行的进程就退出;

实现:System.Diagnostics.Process类的静态方法GetProcessesByName(string processName)

Process[] ps = Process.GetProcessesByName("Guo.exe");

if (ps != null && ps.Length > 1)

{

   //发现重复进程

}

写在Main方法里;判断Length大于1,是因为本身启动之后也在进程列表里了,第一次启动的时候Length==1;

优点:代码简单;

缺点:会把别的重名程序误认为是自己(如很多软件都有update.exe);可以通过复制多个exe并起不同名字来达到运行多个实例的目的;

二.   共享锁(文件、注册表)

原理:运行程序时,在一个公共的位置创建一个共享值(如在固定目录创建一个文件,或者在固定的注册表位置创建一个值),退出程序时删除该值。若运行时发现值已经在,则表示程序已经在运行,此时新运行的进程就退出;

实现:略;

优点:逻辑好理解;

缺点:若程序没有正常退出,共享值没有被删除,会导致程序无法再启动;

三.   线程互斥

原理:通过一个唯一标识创建进程互斥体,启动时判断互斥体是否已经存在,若存在则表示是重复进程;

实现:使用System.Threading.Mutex

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        /// <summary>
        /// 需要定义为类变量,而非局部变量
        /// </summary>
        static System.Threading.Mutex _mutex;

        static void Main(string[] args)
        {
            //是否可以打开新进程
            bool createNew;
            
            //获取程序集Guid作为唯一标识
            Attribute guid_attr = Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute));
            string guid = ((GuidAttribute)guid_attr).Value;
            _mutex = new System.Threading.Mutex(true, guid, out createNew);
            if (false == createNew)
            {
                //发现重复进程
            }
            _mutex.ReleaseMutex();
        }
    }
}

优点:真正能做到同一个程序只允许运行一个进程;

缺点:暂无

注意:如果用不同用户同时登陆windows,仍然可以各自运行一个实例;如果想要不同用户也只能运行一个实例,那么,上面的guid变量需要加上前缀“Global\\”,详细可参看http://www.csharpwin.com/csharpspace/12748r5312.shtml