实验三 Linux进程基本实验

任务概要

  1. 实验题目
    在 Linux 环境下,用 C 语言编写一个程序,以树状结构(即体现父子关系)输出系统当前所有进程。
  2. 实验目的
    • 理解进程和程序、进程和线程的联系与区别;
    • 熟悉进程的重要数据结构、进程的状态、进程管理与控制及实现机制;
    • 练习获取进程执行的相关信息,理解进程的执行过程。
  3. 实验平台
    Vmware Tools 14、Xshell5、Ubuntu16
  4. 实验要求
    在 Linux 下,用 C 语言自己编写一个程序,要求能以树状结构(即能体现父子关系)打印出系统当前的所有进程;独立完成
  5. 设计思路和流程
    • Linux 自带 pstree
    • 编写 pstree,分析思路
    • 编译运行

详细设计

  1. 系统自带 pstree 展示:

pstree 命令以树状图显示进程间的关系(display a tree of processes)。ps 命令可以显示当前正在运行的那些进程的信息,但是对于它们之间的关系却显示得不够清晰。在 Linux 系统中,系统调用 fork()可以创建子进程,通过 shell 也可以创建子进程,Linux 系统中进程之间的关系天生就是一棵树,树的根就是进程 PID 为 1 的 init(systemd)进程。常用的参数如下:(因为 pstree 输出的信息可能比较多,所以最好与 more/less 配合使用。)
格式:pstree
以树状图显示进程,只显示进程的名字,且相同进程合并显示。
格式:pstree -p
以树状图显示进程,还显示进程 PID。
格式:pstree <pid>
格式:pstree -p <pid>
以树状图显示进程 PID 为 <pid> 的进程以及子孙进程,如果有 - p 参数则同时显示每个进程的 PID。
格式:pstree -a
以树状图显示进程,相同名称的进程不合并显示,并且会显示命令行参数,如果有 - p 参数则同时显示每个进程的 PID。

  1. 自行设计 pstree.c,思路
    在 Linux 内核中, /proc 目录是一种文件系统,即 proc 文件系统,存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。/proc 目录中包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号,里面包含对应进程相关的多个信息文件。

本实验参考以上的 pstree 的结构,通过访问 /proc 里面的含有进程号的文件夹,获取进程的信息, 每个文件夹中都含有一个 status,获取其中的 pid,ppid 及 name,从而获取父进程的 id,源程序中的数据结构,是为了方便完成,将获取的文件存入。

将每次读取一个 status 的信息存入到此结构中,将所有的进程文件夹全部存入到数组中,进行结构树的打印。打印过程中若发现其存在子进程, 记录父进程,递归打印子进程,当无子进程时,返回父进程。

  1. 编译运行:
    touch pstree.c


写好的pstree放入其中,vim或直接图形界面复制

gcc -o pstree pstree.c


./pstree

打印出了进程树

proc -A 看到SSH进程号为2014

pstree 2014 -p 显示出的 ssh 进程的父子进程与打印出的进程树的结构显示的是一样的

  1. 实验体会:
    实验结果显示,进程树为层次递进的,父子进程的先后顺序表现得十分明显。所有进程的主进程都是 systemd,每个进程都有其父进程统管。Linux 的子进程的实现是用的 fork(),且可以递归下去。打印的时候,如果下一层没有子进程,则返回父进程。

Linux 使用“进程控制块 (PCB)”的数据结构 task_struct 来代表一个进程, 该结构包含进程的所有信息。所有关联 PCB 通过链表被组织起来, 就形成了父子关系。

  1. 实验源码:

    #include
    #include
    #include
    #include
    #include
    #include
    #include #include
    #include
    
    int s = 0;
    char default_path[1024] = "/proc/";
    typedef struct file_info {
    int pid;
    int ppid;
    char name[1024];
    int flag;
    int rec;
    }info;
    
    int my_getpid(char* str){
    int len = strlen(str);
    char num[10];
    int i,j,ret;
    
    if(strncmp(str,"Pid",3) == 0)
    {
    for(i = 0; i < len; i++) { if(str[i]>='0' && str[i]<='9') break; } for(j = 0;j < len - i;j++) { num[j] = str[i + j]; } num[j] = '\0'; ret = atoi(num); } else ret = 0; return ret; } int my_getppid(char *str) { int len = strlen(str); char num[10]; int i, j, ret; if(strncmp(str,"PPid",4) == 0) { for(i = 0;i < len;i++){ if(str[i] >= '0' && str[i] <= '9') break; } for(j = 0;j < len - i;j++){ num[j] = str[i + j]; } num[j] = '\0'; ret = atoi(num); } else ret = 0; return ret; } void print_pstree(info *file,int count,int ppid,int rec) { int i,j,k; for(i = 0;i < count;i++) { if(file[i].flag == 0 && file[i].ppid == ppid) { file[i].rec = rec + 1; file[i].flag = 1; for(k = 0;k < rec;k++) { printf(" >>>>");
    }
    printf("%s\n", file[i].name);
    print_pstree(file,count,file[i].pid,file[i].rec);
    }
    }
    
    }
    
    int main(){
    int i,j,k,total,s1,s2,count,t;
    char str[1024], dir[1024];
    struct dirent **namelist;
    strcpy(dir, default_path);
    total = scandir(dir,&namelist,0,alphasort);
    printf("path = %s, total = %d\n", dir, total);
    
    for(i = 0; i < total; i++) { strcpy(str, namelist[i]->d_name);
    if(str[0] >= '0' && str[0] <= '9') count++; } printf("process counts is %d\n",count); info file[1024]; i = 0; t = 0; while(i < total) { FILE *fp; char path[1024],name[1024]; int pid,ppid; strcpy(str,namelist[i]->d_name);
    strcpy(path,default_path);
    if(str[0] >= '0' && str[0] <= '9') { strcat(path, str); strcat(path,"/status"); fp = fopen(path,"r"); while(!feof(fp)) { fgets(str, 1024, fp); if((s1 = my_getpid(str)) != 0) { pid = s1; } if((s2 = my_getppid(str)) != 0) ppid = s2; if(strncmp(str, "Name", 4) == 0) { for(j = 4;j < strlen(str);j++) { if(str[j] >= 'a'&&str[j] <= 'z') break; } for(k = j;k < strlen(str);k++) { name[k - j] = str[k]; } name[k - j] = '\0'; } file[t].pid = pid; file[t].ppid = ppid; strcpy(file[t].name,name); } fclose(fp); t++; } i++; } int m; for( m = 0;m < count;m++) { file[m].flag = 0; file[m].rec = 0; } print_pstree(file,count,0,0); return 0; }

本文链接:https://ariser.cn/index.php/archives/10/
本站文章采用 知识共享署名4.0 国际许可协议进行许可,请在转载时注明出处及本声明!