最近项目开发过程中遇到了保证程序只有一个实例存在的需求,也就是只能存在一个exe。本人目前有两种实现的方法。
一、基于Qt的实现
基于Qt的实现是利用了Qt中的共享内存(QSharedMemory),第一个运行的exe创建一个共享内存,后续的程序如果能访问到此内存,就认为已有exe存在了。伪代码如下:
int main()
{
//创建一个共享内存
QSharedMemory sharedMemory;
//设置共享内存的标识,这个标识是确定的
sharedMemory.setKey(strPid);
//尝试去attach由标识符指定的内存块,如果attach成功
//说明这个内存段已经存在了,也就是说已经存在一个exe了那么就可以
if (m_sharedMemory.attach())
{
m_bRunning = true;
return;
}
else
{
m_bRunning = false;
//运行到此,说明还不存在exe,创建一个大小为1的共享内存段
if (!m_sharedMemory.create(1))
{
m_bRunning = true;
}
}
}
二、基于C++的实现
这里是针对windows平台,基于windows的接口实现。是根据名称去查找进程数量,然后进行处理。
//根据进程名称查找进程数量是否大于1
bool testOpenProcess::findProcessIdAccordName(const std::string& proName, QVector<DWORD>& proId)
{
int i = 0;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
i += 0;
}
BOOL bMore = ::Process32First(hProcessSnap, &pe32);
while (bMore)
{
char ansi[512] = { 0 };
WideCharToMultiByte(CP_ACP, 0, pe32.szExeFile, -1, ansi, sizeof(ansi), NULL, NULL);
std::string path = ansi;
std::string appName = proName;
if (stricmp(appName.c_str(), ansi) == 0)
{
//printf("进程运行中");
i += 1;
proId.push_back(pe32.th32ProcessID);
printf("findProcessByName: find a same name exe:%s \n", path.c_str());
//break;
}
//printf(" 进程名称:%s ;saved app name is %s\n", path.c_str(), appName.toStdString().c_str());
bMore = ::Process32Next(hProcessSnap, &pe32);
}
::CloseHandle(hProcessSnap);
if (i > 1)
{ //数量大于1,说明排除自身外,还存在一个同名进程,说明自己不是第一个
printf("findProcessByName : find a exe in task\n");
return true;
}
else
{
//printf("findProcessByName : not find a exe in task\n");
return false;
}
}
int main()
{
QVector<DWORD> appID;
if (findProcessIdAccordName("testOpenProcess.exe", appID))
{
return;
}
//...后续操作
}
三、 linux平台下依赖qt接口实现判断,代码如下:
bool IsAlreadyRunning()
{
QString processName = qApp->applicationName();
int account = 0;
QString cmd = "ps -ef | awk '{print $2,$8,$9,$10,$11}'";
QProcess p;
p.start("bash", QStringList() << "-c" << cmd);
if(!p.waitForFinished()){
return true;
}
QString ret = p.readAllStandardOutput();
QStringList lineList = ret.split("\n");
for(int i = 1; i < lineList.size(); i++){
QString PIDStr = lineList[i].split(" ")[0];
QString programStr = lineList[i].split(PIDStr)[1].trimmed();
QString programTmpPathNotPara = programStr.split(" ")[0];
QStringList processTmpList = programTmpPathNotPara.split("/");
QString programTmpName = processTmpList[processTmpList.size() - 1];
if(programTmpName == processName){
account++;
}
if(account >= 2){
return true;
}
}
return false;
}