寒星轩

There are innumerable stars in the sky, the smallest is me!

用户操作
[即时聊天] [发私信] [加为好友]
李星ID:starlee
207895次访问,排名341好友65人,关注者107
欢迎大家访问我的Blog。
主要是C++,设计模式,面向对象设计方面的技术文章。
starlee的文章
原创 98 篇
翻译 0 篇
转载 45 篇
评论 331 篇
李星的公告
郑重声明

        本BLOG所发表的 原创文章,作者保留一切权利。必须经过作者本人同意后方可转载,并注名作者(StarLee)和出处(CSDN Blog)。
作者Email:
coolstarlee(at)sohu.com
最近评论
陈诚:好象不一样,我这个共两个类,实现类和接口类
深夜才走在路上:实际上使用CLR封送C++类让人很受伤,在mc中有很多C++的特性不能使用,甚至STL都不可用
hfg :错了错了,当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。

不管基类的析构函数是不是virtual ,派生类的析构函数还是会被调用的,区别只是在于基类的析构函数有没有被调用
Forrest Yu:Star Lee:

如果有两个以上的类需要包装,那又应该怎样做呢?
Forrest Yu:CLR 还是很强大的,
一些老的MFC项目可以先手动添加
#include <afx.h>,
其他的可能要加
#include <windows.h>,
然后再用这种方法.
文章分类
收藏
相册
友情链接
houdy的专栏
lijgame的专栏
lyrebing的专栏
禾青谷
存档
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 程序只启动一个实例的几种方法收藏

新一篇: 又有一篇文章登上CSDN首页 | 旧一篇: 我们不是私有财产--《断锁怒潮》观后感

    有些时候,我们要求一个程序在系统中只能启动一个实例。比如,Windows自带的播放软件Windows Medea Player在Windows里就只能启动一个实例。原因很简单,如果同时启动几个实例,却播放不同的文件,那么声音和图像就会引起混乱。在设计模式中,就有一个SINGLETON模式,该模式就是让类只有一个实例。(关于SINGLETON模式,可以看我那篇《重读《设计模式》之学习笔记(三)--SINGLETON模式的疑惑 》)。
    对于程序而言,我们只有在程序启动的时候去检测某个设置,如果程序没有启动,就把设置更新为程序已经启动,然后正常启动程序;如果程序已经启动,那么就终止程序的启动。在程序退出的时候把设置恢复为程序没有启动。按照上面的思路,我们很容易就能想出下面的两种方法:
    一,文件法
    在硬盘上创建一个文件,在文件里设置一个值,根据这个值来判断程序是否已经启动。
    二,注册表法
    在注册表中创建一个键,根据该键的键值来决定是否要启动程序。
    但是,上面的两种方法,都有I/O操作。我觉得这不是最好的方法。下面就介绍两种不用I/O操作的方法。思路跟上面是一样的,在进程启动的时候去检测某个设置是否继续启动进程。由于要判断同一个程序是否已经启动一个实例,也就是说会有两个进程去访问同一个设置,所以该设置应该是可以夸进程访问的,比如上面两种方法中的文件和注册表。我们在用VC进行开发时,还可以用文件映射和互斥量。下面是详细的说明:
    VC在创建工程的时候,会自动创建一个App的类。比如,你的工程名是StarLee,那么这个App类的类名就是CStarLeeApp。在进程启动和退出的时候会分别调用该类的两个方法:InitInstance()和ExitInstance()。所以,我们的代码都是添加在这两个方法里面的。
    三,文件映射法
    首先,给App类加上一个成员变量: 

HANDLE m_hFileMapping;

    然后,在App类的InitInstance()方法的最前面加上下面的代码:

m_hFileMapping = CreateFileMapping(NULL, NULL, PAGE_READONLY, 013"StarLee");

// 检测是否已经创建FileMapping
// 如果已经创建,就终止进程的启动
if ((m_hFileMapping != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
{
    CloseHandle(m_hFileMapping);
    
    MessageBox(NULL, 
"该进程已经启动""错误", MB_OK);

    
return FALSE;
}

    最后,在App类的ExitInstance()方法里加上下面的代码:

if (m_hFileMapping != NULL)
    CloseHandle(m_hFileMapping);

    四,互斥量法
    首先,给App类加上一个成员变量:

HANDLE m_hMutex;

    然后,在App类的InitInstance()方法的最前面加上下面的代码:

m_hMutex = CreateMutex(NULL, TRUE, "StarLee"); 

// 检测是否已经创建Mutex
// 如果已经创建,就终止进程的启动
if ((m_hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS)) 
{
    ReleaseMutex(m_hMutex);

    MessageBox(NULL, 
"该进程已经启动""错误", MB_OK);
 
    
return FALSE;
}

    最后,在App类的ExitInstance()方法里加上下面的代码:

if (m_hMutex != NULL)
{
    ReleaseMutex(m_hMutex);
    CloseHandle(m_hMutex);
}

    上面两种方法的思路和代码添加的步骤都是一样的,当然效果也一样,选择任何一种方法都能达到让进程只启动一个实例的目的。

发表于 @ 2007年03月20日 09:26:00|评论(loading...)|编辑

新一篇: 又有一篇文章登上CSDN首页 | 旧一篇: 我们不是私有财产--《断锁怒潮》观后感

评论

#axman 发表于2007-03-20 16:42:57  IP: 210.82.61.*
上面这些方法都有缺点,简单说就是设置标记.
如果一个进程启动后设置了这些标记,有一个异常情况就是进程被强行中断没有将标记恢复,则后面的其它进程再也不能启动.

其实相同进程要看是否已经有实例,只要列举是否已经存在同名进程即可.因为你自己可以把进程名定义成唯一的,这样如果有实例就可以被列举出来.
#yesry 发表于2007-03-20 17:39:38  IP: 218.80.71.*
上述方法都是存在一个问题:前一个实例被意外DOWN后,系统没有立即收回资源的,尤其是文件映射法和互斥量法。在运行关键任务的时候容易掉链子。

我建议用双料,文件锁定和互斥量法。
#CoolHg 发表于2007-03-20 18:05:58  IP: 211.94.157.*
还可以使用共享变量的方式
#lwd2k 发表于2007-03-20 21:18:29  IP: 221.215.49.*
应该加上axman的实例法。
#ArcadiaRay 发表于2007-03-21 10:20:00  IP: 60.28.128.*
就是使用创建命名内核对象的方式最好,可以给一个应用程序创建一个 GUID 来表示内核对象的名称.
#axman 发表于2007-03-21 13:10:04  IP: 210.82.61.*
这应该是一个设计方案而不是一个技术,某个技术并不能完全可靠.
不知道你们是否了解qmail的设计.它就是多进程相互监视,如smtp发现pop3服务没有了就会自动启动pop3,而pop3也会监视smtp,当然如果有三个以上的进程互相监视其它进程就更可靠.

反过来也一样,如果要保证一个进程只有唯一实例,可以用一个辅助进程看它的标记和这个进程本身,如果标记已经置为启动状态而这个进程却找不到了那就说明它被意外中止了,辅助进程可以帮助复位标记.反过来唯一实例的进程也会检查辅助进程是否还在工作如果不在了就启动它以确保唯一实例的主进程能正确地恢复标记.如果同时多个辅助进程在工作就更可靠了,这些辅助进程仅仅定时做状态检查,性能影响可以忽略.但就使程序非常可靠.同时多个进程都被强行中断的可能性不大,就象双机热备份,你说双机同时当了的可能性就不大,三台同时当了的可能性更小,除非同时断电了.
#NewVC1978 发表于2007-03-21 22:53:06  IP: 218.81.202.*
我通常用Setprop设置窗口属性,然后启动时刻判断。
#breakind 发表于2007-03-21 23:01:50  IP: 58.49.198.*
还是觉得监控比较好
#rfa 发表于2007-03-22 11:11:54  IP: 218.247.215.*
不存在楼下的兄弟所说的顾虑,其实无论mutex也好event也好它们都隶属于创建者进程的,会随着创建者的销毁而销毁,也就是说假如进程A创建了mutex1或者event2,那么当进程A结束(无论主动还是意外结束),windows会自动释放它们.

另外,枚举进程名称并不是稳妥办法,例如c:\a.exe和d:\a.exe都在运行,那么就一定会枚举出2个a.exe,多余的话我就不说了.

总而言之,mutex是最好的解决办法,也是人家MS推荐的做法.
#xiaxilin 发表于2007-03-22 16:14:38  IP: 221.224.21.*
例如c:\a.exe和d:\a.exe都在运行,那么就一定会枚举出2个a.exe,多余的话我就不说了.


====
此言差矣,枚举进程不只看到进程名,而且可以找到进程的文件名(包括路径),这样不会有上述问题

不过,如果用户如果把你的文件如a.exe拷贝一个a1.exe,先运行第一个,再运行第二个,这样这个办法就没有用了!
#missdeer 发表于2007-03-27 20:26:39  IP: 58.60.39.*
内存映射文件才是最安全的方法,互斥也可以,即使前一个实例意外down掉,系统也会及时回收资源的。只有用Atom系统才会回收不了。
另外文中还没提到可以用信号量,以及有回复中说到的事件。
#haoahua 发表于2007-06-02 21:48:10  IP: 59.52.86.*
效果不错..
#weizhicheng 发表于2007-07-04 21:46:22  IP: 219.148.131.*
还行吧。
发表评论  


登录
Csdn Blog version 3.1a
Copyright © 李星