0. 前言
linux
系统中,在 /proc
文件系统中,每个运行中的进程都有一个相应的目录,其名称是进程的PID。在这个目录下,有一个名为status
的文件,其中包含了有关该进程的各种信息,包括进程号。
status
文件中包含的信息(部分截选):
本人只完成了基础的打印功能,按进程号排序打印没有实现。
1.主函数
主函数通过读取命令行参数,来判断功能。(本人判断的方法比较low,使用switch)
typedef struct {
int processID;
char processName[256];
int parentID;
int parentIndex; //父亲在列表中的下标(因为使用数组维护,所以要有下标)
struct Process* children[100]; //假设每个进程最多有100个孩子
int childrenCnt;
} Process;
int main(int argc, char *argv[]) {
Process processList[500]; //创建进程集合,最多500个进程
for(int i = 0; i < 500; i++) {
processList[0].parentIndex = -1;
}
int opcode = 0;
int count = 0;
for (int i = 0; i < argc; i++) {
assert(argv[i]);
printf("argv[%d] = %s\n", i, argv[i]);
if(strncmp(argv[i], "-p", 2) == 0 || strncmp(argv[i], "--show-pids", 11) == 0) {
opcode = 1;
break;
}
if(strncmp(argv[i], "-n", 2) == 0 || strncmp(argv[i], "--numeric-sort", 14) == 0) {
opcode = 2;
break;
}
if(strncmp(argv[i], "-V", 2) == 0 || strncmp(argv[i], "--version", 9) == 0) {
opcode = 3;
break;
}
}
assert(!argv[argc]);
switch(opcode) {
case 1: getProcessList(processList, &count);
//display(processList, &count);
buildProcessTree(processList, &count);
displayTree(&processList[0], 0, 0);
break;
case 2: break;
case 3: break;
default:
printf("Display a tree of processes.\n");
printf(" -p, --show-pids\tshow PIDs\n");
printf(" -n, --numeric-sort\tsort output by PID\n");
}
printf("There are %d processes\n", count);
return 0;
}
2.打印进程数
2.1 获取进程数组
获得所有进程,保存至主函数创建的数组中。
具体为读取status
文件的内容,识别并保存进程基本信息。
void getProcessList(Process* processList, int* count) {
assert(count);
//*count = 0;
int cnt = 0;
assert(processList);
DIR* procDir = opendir("/proc");
assert(procDir);
struct dirent* entry;
while((entry = readdir(procDir)) != NULL) {
if(entry->d_type == DT_DIR && isNumeric(entry->d_name)) {
char statusPath[512];
char line[256];
FILE* statusFile;
snprintf(statusPath, sizeof(statusPath), "/proc/%s/status", entry->d_name);
statusFile = fopen(statusPath, "r");
//逐行读取文件内容
while(fgets(line, sizeof(line), statusFile) != NULL) {
if (strncmp(line, "Name:", 5) == 0) {
sscanf(line, "Name:\t%s", processList[cnt].processName);
}
if(strncmp(line, "Pid:", 4) == 0) {
sscanf(line, "Pid:\t%d", &processList[cnt].processID);
}
if(strncmp(line, "PPid:", 5) == 0) {
sscanf(line, "PPid:\t%d", &processList[cnt].parentID);
}
}
cnt++;
fclose(statusFile);
}
}
*count = cnt;
closedir(procDir);
}
2.2 创建进程树
遍历数组,获得每个进程的父进程在数组中的下标(因为数组中的内容要通过下标访问),这里因为遍历出来的进程其父进程的ID号是递增的,所以直接使用二分法查找。
int getParentIndex(Process* processList, int i) {
//查找父亲在列表中的下标,查找范围是0 ~ i-1之间, 二分法查找
int a = 0, b = i - 1;
//查找是左闭右开, 所以对于右端点需要单独验证
while (b >= a + 1) {
if(processList[b].processID == processList[i].parentID)
return b;
int k = (b - a) / 2 + a;
if(processList[k].processID == processList[i].parentID)
return k;
else if(processList[k].processID > processList[i].parentID)
b = k;
else if(processList[k].processID < processList[i].processID)
a = k;
}
return -1;
}
void buildProcessTree(Process* processList, int* count) {
// ProcessNode* root = creatProcessNode(processList[0].processName, processList[0].processID);
int max = 0;
for(int i = 0; i < *count; i++) {
int index = getParentIndex(processList, i);
if(index == -1 || index == 1) continue;
//Process proc = processList[index];
processList[index].children[processList[index].childrenCnt++] = (struct Process*)&processList[i];
//processList[index].childrenCnt++;
if(processList[index].childrenCnt > max)
max = processList[index].childrenCnt;
assert(processList[index].childrenCnt <= 100); //孩子树的数量不能超过100
}
}
2.3 排版显示
这里本人调试了很久,还是没弄出来555555,排版太难了
void displayTree(Process* proc, int tabCnt, bool isFirst) {
if(isFirst)
printf("|");
else {
for(int i = 0; i < tabCnt; i++) {
printf("\t");
}
}
printf("%s(%d)(%d)", proc->processName, proc->processID, proc->parentID);
if(proc->childrenCnt == 0) {
printf("\n");
return;
}
for(int i = 0; i < proc->childrenCnt; i++) {
if(i == 0)
isFirst = 1;
else
isFirst = 0;
displayTree((Process*)proc->children[i], tabCnt + 2, isFirst);
}
}