通常这种需求是特有的一些软件只能在当前操作系统中运行单实例,以保证某些功能不冲突。
以下回顾遇到过的几种方法:
1、TCP绑定一个特有端口,进程初始化后判断该端口是否已绑定来确认当前操作系统是否已启动另一实例。
优点是实现非常简单,实现逻辑也就那么几行代码;
缺点嘛,网络端口就65535个,万一哪天有人冲突了,这个进程就永远走不下去了。
个人经历过一家专有行业,软件在相对封闭体系里面运行,业务及业主保证不可能有其他太多家的软件跑在环境里,所以采用了这种办法。
2、文件标记。
类似增加一个固有地址的配置文件,增加一个启动字段标识当前程序是启动还是关闭。
优点也是实现简单
缺点比网络端口方式更明显一点,万一程序恶意关闭或者崩溃,或者手工改了状态位,一样启动不了。
相对的进阶版本或许是打注册表了,但是同样会有以上提到的这个缺点。
3、内核对象。
windows内核对象,有一部分可以命名,而且使用的是操作系统级的同一名字空间,常用的包括Mutex,Semaphore,Evenr等,以Event为例:
1 WINBASEAPI 2 _Ret_maybenull_ 3 HANDLE 4 WINAPI 5 CreateEvent( 6 _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, 7 _In_ BOOL bManualReset, 8 _In_ BOOL bInitialState, 9 _In_opt_ LPCSTR lpName 10 );
创建接口最后一个参数lpName为命名字符串,标准长度为MAX_PATH-260个字符。确保唯一性这里通常使用一个自生成的GUID为名字。
进程启动初始化完毕后调用OpenEventW
WINBASEAPI
_Ret_maybenull_
HANDLE
WINAPI
OpenEvent(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ LPCWSTR lpName
);
相应有个参数lpName,传入之前给的GUID就可以在当前系统中查询有没有正在使用这个GUID对应的Event对象,如果该函数返回NULL, 通过判断GetLastError()返回2-ERROR_FILE_NOT_FOUND来确认没有使用。
目前遇到过的有这三种,后续有新方法再新增。
安全性最高的当属第三。