当前位置: 首页 > news >正文

操作系统课程设计:3-打印进程树

1.实验目的

1.了解proc文件系统

2.理解task_struct结构及内核进程控制块链表遍历机制

3.采用添加内核模块技术和访问/proc目录方法,打印进程树

2.实验截图及结果分析

(1)实验截图

①访问/proc目录方法打印进程树

②添加内核模块技术打印进程树

(2)实验结果分析

从实验截图结果来看,通过访问/proc目录和添加内核模块这两种方式,均成功打印出了proc文件中包含的进程信息,且在进程树层级结构的呈现效果上各有特点。

用户态编程(访问/proc目录方法)通过编写的pstree.c代码,实现了从/proc下各进程status文件中读取、解析关键信息,my_getpid和my_getppid函数成功提取出进程的PID和PPID,特定的字符串处理逻辑解析出进程名,在print_pstree函数里,借助统计子进程数量和记录已打印子进程数,依据递归深度精准控制缩进和连接符的打印,最终呈现的进程树清晰展示了进程名、进程id和父进程id,层级结构一目了然,父子进程关系清晰可辨,极大方便了对进程间关系的理解和分析。

内核态编程(添加内核模块技术)中,pstree2.c的print_tree2函数借助list_for_each遍历cur->children链表,运用深度优先算法递归打印子进程,从实验截图的打印结果来看,不仅呈现了进程名,还包含了PID号,并且通过缩进和特定符号形成了树形结构,清晰体现了进程间的层级关系,让进程树的展示更加直观,既保留了内核态遍历的高效性,又通过补充PID和优化结构增强了信息的完整性和可读性。

3.实验程序

(1)访问/proc目录方法打印进程树

pstree.c

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <pthread.h> #include <unistd.h> #include <dirent.h> char default_path[1024] = "/proc/"; int s = 0; typedef struct file_info { int pid; int ppid; char name[1024]; int flag; int rec; } info; // 从字符串中提取 PID 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]; } ret = atoi(num); } else ret = 0; return ret; } // 从字符串中提取 PPID 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]; } ret = atoi(num); } else ret = 0; return ret; } // 检查是否存在指定父进程 ID 的子进程 int child_exist(info *file, int count, int ppid) { int i; for (i = 0; i < count; i++) { if (file[i].flag == 0 && file[i].ppid == ppid) return 1; } return 0; } // 递归打印进程树 void print_pstree(info *file, int count, int ppid, int rec) { int i, j, k; int child_count = 0; // 记录当前父进程下子进程数量 int printed_child = 0; // 记录已打印子进程数量 // 统计子进程数量 for (i = 0; i < count; i++) { if (file[i].flag == 0 && file[i].ppid == ppid) { child_count++; } } 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++) { if (k < rec - 1) { printf("│ "); } else { if (printed_child == child_count - 1) { printf(" "); } else { printf("├── "); } } } printf("[%d]%s\n", file[i].pid, file[i].name); print_pstree(file, count, file[i].pid, file[i].rec); printed_child++; } } } 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); count = 0; for (i = 0; i < total; i++) { strcpy(str, namelist[i]->d_name); if (str[0] >= '0' && str[0] <= '9') count++; } printf("进程数:%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 - 1] = '\0'; } file[t].pid = pid; file[t].ppid = ppid; strcpy(file[t].name, name); } fclose(fp); t++; } i++; } // 初始化标志位和递归深度 for (i = 0; i < count; i++) { file[i].flag = 0; file[i].rec = 0; } print_pstree(file, count, 0, 0); return 0; }

(2)添加内核模块技术打印进程树

pstree2.c

#include<linux/module.h> #include<linux/sched.h> #include<linux/list.h> typedef struct task_struct ts; // 递归打印进程树 void print_tree2(ts *cur,int blanks){ int i; for(i=1;i<=blanks;i++) printk(" "); printk("%s\n",cur->comm); struct list_head *list; list_for_each(list,&cur->children){ ts *p=list_entry(list,struct task_struct,sibling); print_tree2(p,blanks+4); } } // 模块初始化函数 int init_pstree2(void){ ts *cur; // 找到 init 进程(PID 为 1) for(cur = current; cur->pid != 1; cur = cur->parent); print_tree2(cur,0); return 0; } // 模块退出函数 void exit_pstree2(void){ } // 注册模块初始化函数 module_init(init_pstree2); // 注册模块退出函数 module_exit(exit_pstree2);

② Makefile

obj-m := pstree2.o KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o .*.cmd *.ko *.mod.c
http://www.cnnetsun.cn/news/135813.html

相关文章:

  • 7、Windows应用开发中的用户界面控件使用指南
  • 18、Windows 应用数据管理全解析
  • AI大模型微调完全指南:13分钟让小模型“开挂“超越GPT-5,程序员必备收藏!
  • 汇编语言全接触-34.RichEdit 控件:更多的正文操作
  • 汇编语言全接触-35.RichEdit 控件:语法高亮显示
  • 自养号测评:跳出“隐形工具”定位,筑牢品牌增长核心基建
  • 昂瑞微推出了面向移动电源行业的一站式智能方案-OM70201MV
  • Mobox移动桌面体验优化指南:极致显示与性能调校
  • 23、Web与互联网管理及服务器日志分析
  • LPxxR100FN_36W/48W/60W开关电源100V同步整流芯片典型应用电路(LP20R100FN,LP20R100FN,LP10R100FN)
  • SHP文件GCJ02转WGS84坐标系系统源码
  • ComfyUI智能字幕生成终极指南:轻松为图片添加精准描述 [特殊字符]
  • ComfyUI智能字幕生成终极指南:3步实现AI自动化图片标注
  • 2025亚马逊运营升级:从短期竞争,转向品牌资产长效经营
  • 【大前端】【iOS】iOS 真实项目可落地目录结构方案
  • “在我电脑上明明是好的”:我用这套云原生工作流,终结了团队内耗
  • 揭秘MCP服务发现:构建智能AI工具生态系统的核心技术
  • 智能笔记管理:如何高效组织你的每日任务与灵感
  • 终极指南:如何快速掌握 My Mind 免费在线思维导图工具
  • Vim插件管理器VAM终极指南:从零开始构建高效开发环境
  • AgentWeb终极指南:Android混合开发的一站式解决方案
  • 事件循环机制
  • TikTok 电商全球新棋局:从野蛮生长到精耕细作,谁能站稳脚跟?
  • 创建Mysql 用户 并赋权
  • 完整指南:如何快速掌握Vue可视化打印解决方案
  • Three-DXF深度解析:在浏览器中实现专业级CAD文件渲染
  • P2MS:比特币的多重签名机制与比特鹰的技术解析
  • 终极AI字幕生成指南:快速掌握智能字幕处理技巧
  • C语言程序设计教学指导:突破误区,设计有效实验项目
  • DirectX 9.0b SDK介绍:核心组件、在游戏中的重要性