一、知识点储备
环境:centos6 , x86,g++
需求:输入参数:进程名和超时时间;功能:杀死超时的进程
- 杀死进程的方法:前期考虑用boost::process库以达到跨平台的目的,但是学习之后发现该库是用来管理子进程的,不能用来杀死一个不相干的进程。在linux中杀死一个进程可以使用kill(pid,SIGKILL)函数通过发送信号实现杀死进程的目的。
#include<sys/types.h>
int kill(int pid, int SIG); //第一个参数是进程的id,第二个参数是发送的信号,返回值:0--成功
2.根据进程名获得进程pid
linux系统中所有正在运行的进程都会在/proc/路径下拥有一个以自身pid命名的文件夹,文件夹中存储了该进程相关的一些信息,其中:
exe:是该进程所运行的程序的软连接;
cmd:是该程序所在的目录
status文件(/proc/***pid***/status)
:文件中第一行标明了该进程对应的进程名。
所以可以通过遍历/proc/下所有文件夹中的status的方式获取到该进程名对应的所有进程pid
(所谓的进程名就是执行的程序的名字,一个程序可以同时有多个进程去运行,所以一个名字可能对应多个进程pid)
3. 获取进程的运行时长
目前我查到的信息来看,没找到一个封装好的c++函数可以让我们方便得得到一个进程得运行时长,linux中普遍是通过ps命令来获取到进程的开始时间和运行时长。所以在c++中通过代码来启动命令行来得到结果并将获取到的时间变成总秒数
//将此命令中的pname和pid分别替换成自己的进程名和进程pid即可
//得到的就是一个"日-时:分:秒"结构的运行时长
ps -eo pid,etime,cmd | grep [pname] | grep [pid] | awk '{print $2}'
二、以下是各部分的实现代码
1.获取进程pid
//获取进程pid
vector<string> ProcessKiller::getPidFromName(std::string ProcessName){vector<string> pids;const char* cprocessName=ProcessName.c_str();DIR *dir;struct dirent *ptr;FILE *fp;char filepath[50];//存放cmline文件路径char cur_task_name[50];//存放命令行文本char buf[BUF_SIZE];dir = opendir("/proc"); //打开路径,读取下面每一个文件夹if (NULL != dir){while ((ptr = readdir(dir)) != NULL) {//如果是"."或者".."就跳过if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))continue;if(DT_DIR!=ptr->d_type)continue;sprintf(filepath,"/proc/%s/status",ptr->d_name); fp = fopen(filepath, "r");//打开status文件if (NULL != fp){if( fgets(buf, BUF_SIZE-1, fp)== NULL ){fclose(fp);continue;}sscanf(buf,"%*s %s",cur_task_name);//status中的进程名与要杀死的进程名是否匹配if(!strcmp(cprocessName,cur_task_name)){printf("PID: %s\n",ptr->d_name);pids.push_back(ptr->d_name);}fclose(fp);}}vector<string>::iterator it;std::cout<<cprocessName<<" --pids: ";for(it=pids.begin();it!=pids.end();it++){std::cout<<*it<<" ";}std::cout<<std::endl;closedir(dir);}return pids;}
2.获取进程的运行时长(秒数)
这一段代码较长,放到下一篇了
获取进程运行时长
3.杀死进程
void ProcessKiller::killProcess(vector<string> pids,vector<string> &pids_failed){vector<string>::iterator it;for(it=pids.begin();it!=pids.end();it++){std::cout<<*it<<" ";int num;sscanf((*it).c_str(), "%d", &num);long runtime=get_process_runtime(num, m_processName.c_str()); //get pid's running time;if(runtime>m_timeout){if(isRunning(num)==0){printf("%d is running,start to kill it\n",num);int retval = kill(num, SIGKILL); //发送SIGKILL信号给进程,要求其停止运行if (retval<0) //判断是否发生信号{printf("kill %d failed",num);pids_failed.push_back(*it);}else{printf("%d killed\n", num);}}}else{printf("œø³Ì[ %d ]runtime<timeout, this is no need to kill it\n ",num);}}
}
4.判断进程是否在运行
// 0 : running, -1 : exit, -2 : zombie(僵尸进程)int ProcessKiller::isRunning(int pid){if (0 == kill(pid, 0)){std::string path = std::string("/proc/") + std::to_string(pid) + "/status";std::ifstream fs;fs.open(path);if (!fs)return -1;std::string line;while (getline(fs, line)){std::size_t found = line.find("State:");if (found == std::string::npos)continue;else{found = line.find("zombie");if (found == std::string::npos)return 0;elsereturn -2; // zombie}}}elsereturn -1;}