尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

第11天:进程基础内核认知:PCB与task_struct结构体解析

第11天:进程基础内核认知:PCB与task_struct结构体解析
📅 发布时间:2026/6/29 18:16:52

导语:进程的"身份证"

如果把Linux系统比作一座繁华的城市,那么进程就是这座城市中形形色色的居民。每一个居民都有一张独特的身份证,记录着姓名、住址、职业等信息。而操作系统内核则为每一个运行的进程颁发了一张特殊的"身份证"——进程控制块(PCB)。

在Linux内核中,这个PCB的实现就是大名鼎鼎的task_struct结构体。它是内核管理进程的核心数据结构,包含了进程的所有信息:从进程状态、优先级,到内存映射、打开的文件描述符,甚至包括信号处理和命名空间等。今天,让我们深入内核源码,探索这个庞大而精密的task_struct结构体。


一、进程与PCB基础概念

1.1 什么是进程

进程(Process)是Linux系统中最基本的执行单元,是程序的一次执行实例。

# 查看当前系统进程 ps aux # 查看进程数 ps aux | wc -l # 查看特定进程 ps -ef | grep bash

进程的五大特性:

  • 并发性:多个进程可同时运行
  • 动态性:进程具有创建、运行、暂停、终止的生命周期
  • 独立性:每个进程有独立的地址空间
  • 异步性:进程执行顺序不可预测
  • 结构性:进程由PCB和数据段组成

1.2 PCB的作用

**进程控制块(PCB, Process Control Block)**是操作系统用于管理进程的核心数据结构:

┌─────────────────────────────────────────┐ │ 进程控制块 (PCB) │ ├─────────────────────────────────────────┤ │ 进程标识 (PID, PPID, UID, GID) │ │ 进程状态 (就绪/运行/阻塞/终止) │ │ 调度信息 (优先级、调度策略) │ │ 内存信息 (页表指针、段表指针) │ │ I/O状态 (打开文件表、I/O设备) │ │ 计时信息 (运行时间、创建时间) │ │ 信号处理 (信号屏蔽、信号处理函数) │ │ ... │ └─────────────────────────────────────────┘

1.3 Linux中的PCB

在Linux内核中,PCB由task_struct结构体实现,每个进程或线程都对应一个task_struct。

# 查看进程PID echo $$ # 查看进程状态 cat /proc/$$/status

二、task_struct结构体深度解析

2.1 task_struct源码位置

在Linux 6.x内核源码中,task_struct定义于:

# 内核源码路径(取决于安装位置) ls /usr/src/linux-*/include/linux/sched.h

2.2 task_struct核心字段

struct task_struct { volatile long state; // 进程状态 void *stack; // 进程内核栈 unsigned int flags; // 进程标志 int pid; // 进程标识符 int tgid; // 线程组标识符 struct task_struct __rcu *parent; // 父进程 struct list_head children; // 子进程链表 struct list_head sibling; // 兄弟链表 struct mm_struct *mm; // 内存描述符 struct files_struct *files; // 文件描述符表 struct signal_struct *signal; // 信号描述符 const struct cred *cred; // 进程凭证 struct sched_entity se; // 调度实体 struct sched_rt_entity rt; // 实时调度实体 int prio; // 动态优先级 int static_prio; // 静态优先级 int normal_prio; // 正常优先级 unsigned int rt_priority; // 实时优先级 char comm[TASK_COMM_LEN]; // 进程命令名 struct pid_link pids[PIDTYPE_MAX]; // PID链表 struct fs_struct *fs; // 文件系统信息 struct files_struct *files; // 打开文件表 struct nsproxy *nsproxy; // 命名空间 struct thread_struct *thread; // 处理器特定状态 struct list_head tasks; // 全局任务链表 struct wake_q_node wake_q; // 唤醒队列节点 };

2.3 关键字段详解

2.3.1 进程状态
// 进程状态定义(include/linux/sched.h) #define TASK_RUNNING 0x00000000 // 运行或就绪 #define TASK_INTERRUPTIBLE 0x00000001 // 可中断睡眠 #define TASK_UNINTERRUPTIBLE 0x00000002 // 不可中断睡眠 #define TASK_STOPPED 0x00000004 // 已停止 #define EXIT_ZOMBIE 0x00000080 // 僵尸状态 #define EXIT_DEAD 0x00000100 // 死亡状态
# 查看进程状态 cat /proc/1/status | grep -E "State:|State" # 状态含义 # R: 运行 (TASK_RUNNING) # S: 可中断睡眠 (TASK_INTERRUPTIBLE) # D: 不可中断睡眠 (TASK_UNINTERRUPTIBLE) # T: 停止 (TASK_STOPPED) # Z: 僵尸 (EXIT_ZOMBIE)
2.3.2 进程标识
struct task_struct { int pid; // 进程ID,每个进程唯一 int tgid; // 线程组ID,同一线程组的所有线程共享 struct task_struct *parent; // 父进程指针 struct list_head children; // 子进程链表头 struct list_head sibling; // 兄弟进程链表节点 };
# 查看进程PID和PPID ps -ef # PID: 进程ID # PPID: 父进程ID # UID: 用户ID # EUID: 有效用户ID
2.3.3 内存管理
struct task_struct { struct mm_struct *mm; // 内存描述符 struct mm_struct *active_mm; // 当前活跃的内存描述符 }; struct mm_struct { struct vm_area_struct *mmap; // 虚拟内存区域链表 struct rb_root mm_rb; // VMA红黑树 unsigned long total_vm; // 总虚拟页数 unsigned long locked_vm; // 锁定页数 unsigned long pinned_vm; // 钉住页数 unsigned long shared_vm; // 共享页数 unsigned long exec_vm; // 可执行页数 unsigned long stack_vm; // 栈页数 pgd_t *pgd; // 页全局目录指针 atomic_t mm_users; // 使用该地址空间的线程数 atomic_t mm_count; // 主引用计数 };
# 查看进程内存映射 cat /proc/$$/maps # 查看进程内存状态 cat /proc/$$/status | grep -E "Vm|Rss" # VmPeak: 虚拟内存峰值 # VmSize: 虚拟内存大小 # VmRSS: 物理内存占用
2.3.4 文件描述符
struct task_struct { struct files_struct *files; // 文件描述符表 }; struct files_struct { atomic_t count; // 引用计数 struct fdtable *fdt; // 文件描述符表 struct file * fd_array[NR_OPEN_DEFAULT]; // 默认文件描述符数组 }; struct file { union { struct llist_node fu_llist; // 链表节点 struct rcu_head fu_rcuhead; // RCU头 } f_u; struct path f_path; // 文件路径 struct inode *f_inode; // 关联的inode const struct file_operations *f_op; // 文件操作 unsigned int f_flags; // 文件标志 fmode_t f_mode; // 文件模式 loff_t f_pos; // 文件位置 void *private_data; // 私有数据 };
# 查看进程打开的文件 ls -la /proc/$$/fd # 查看文件描述符限制 ulimit -n # 查看进程fd使用情况 cat /proc/$$/limits | grep "Max open files"

三、task_struct的组织与管理

3.1 全局任务链表

Linux内核维护一个全局任务链表,通过task_struct的tasks成员连接所有进程。

struct task_struct { struct list_head tasks; // 全局任务链表节点 }; // 内核全局变量 struct task_struct *init_task; // init进程(PID=1) // 遍历所有进程 #define for_each_process(p) \ for (p = &init_task; (p = next_task(p)) != &init_task; )
# 查看init_task地址 cat /proc/1/attr/current 2>/dev/null || echo "Permission denied" # 任务链表操作示例(需要内核调试) # grep -A 5 "struct task_struct" /boot/config-$(uname -r)

3.2 PID哈希表与链表

enum pid_type { PIDTYPE_PID, // 进程ID PIDTYPE_TGID, // 线程组ID PIDTYPE_PGID, // 进程组ID SID, // 会话ID PIDTYPE_MAX }; struct pid_link { struct hlist_node node; struct pid *pid; }; struct task_struct { struct pid_link pids[PIDTYPE_MAX]; // 多种PID关联 };
# 查看进程的多种ID ps -eo pid,pgid,sid,tty,comm # PID: 进程ID # PGID: 进程组ID # SID: 会话ID

3.3 进程调度实体

struct sched_entity { struct load_weight load; // 负载权重 struct rb_node run_node; // 红黑树节点 unsigned int on_rq; // 是否在运行队列 u64 exec_start; // 开始执行时间 u64 sum_exec_runtime; // 累计执行时间 u64 vruntime; // 虚拟运行时间(CFS) u64 prev_sum_exec_runtime; // 上次累计运行时间 u64 last_wakeup_time; // 上次唤醒时间 u64 avg_overlap; // 平均重叠时间 }; struct task_struct { struct sched_entity se; // 普通调度实体 struct sched_rt_entity rt; // 实时调度实体 int prio; // 动态优先级 int static_prio; // 静态优先级 int normal_prio; // 正常优先级 unsigned int rt_priority; // 实时优先级 };

四、进程的创建与销毁

4.1 fork/exec机制

Linux通过fork()和exec()系统调用创建新进程:

fork()工作流程 ┌─────────────────────────────────────┐ │ 1. 分配新的PCB (task_struct) │ │ 2. 复制父进程地址空间 │ │ 3. 复制父进程文件描述符表 │ │ 4. 复制父进程信号处理方式 │ │ 5. 设置新进程的PID、PPID │ │ 6. 返回子进程PID给父进程 │ └─────────────────────────────────────┘
// fork系统调用实现(简化) long do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; // 1. 分配新的task_struct p = copy_process(clone_flags, stack_start, stack_size, parent_tidptr, child_tidptr, NULL); if (!IS_ERR(p)) { // 2. 唤醒新进程 wake_up_new_task(p); } return pid; }

4.2 进程退出

// 进程退出时的清理工作 void do_exit(long code) { struct task_struct *tsk = current; // 1. 设置退出码 tsk->exit_code = code; // 2. 释放资源 exit_mm(tsk); // 释放内存 exit_files(tsk); // 释放文件描述符 exit_fs(tsk); // 释放文件系统 exit_io(tsk); // 释放I/O // 3. 设置僵尸状态 tsk->exit_state = EXIT_ZOMBIE; // 4. 通知父进程 notify = hlist_empty(&tsk->children); tsk->exit_signal = SIGCHLD; write_lock_irq(&tasklist_lock); tsk->state = TASK_DEAD; write_unlock_irq(&tasklist_lock); // 5. 调度其他进程 schedule(); }

五、进程状态查看实践

5.1 通过proc文件系统查看

# 查看进程完整状态 cat /proc/$$/status # 关键字段说明 # Name: 命令名 # State: 进程状态 # Pid: 进程ID # PPid: 父进程ID # Uid/Gid: 用户/组ID # VmPeak/VmSize: 虚拟内存峰值/当前 # VmRSS: 物理内存占用 # Threads: 线程数 #FDSize: 文件描述符表大小

5.2 结构化查看

# 以更友好的格式查看进程信息 ps -eo pid,state,ppid,comm --sort=pid # 状态说明 # R: 运行状态 # S: 睡眠状态 # D: 不可中断睡眠 # T: 停止状态 # Z: 僵尸状态 # 查看进程树 pstree -p # 查看进程详细信息 cat /proc/1/sched

互动讨论

  1. 进程vs线程:Linux中进程和线程都使用task_struct表示,它们本质上有什么区别?在哪些场景下应该选择多进程而非多线程?

  2. 僵尸进程危害:如果父进程没有正确调用wait()回收子进程,会产生僵尸进程。在实际项目中,您是否遇到过僵尸进程问题?是如何排查和解决的?


请帮忙点赞收藏+关注,内容持续更新,感谢大家~~~

相关新闻

  • FreeRTOS源码详解(九)——Notification
  • 一线观察:激光焊接机器人自动上下料半年实录
  • [Android]appops

最新新闻

  • 集合API
  • Ubuntu 26.04部署 DNS 服务器
  • 济南装修口碑哪家强?
  • 首页超出区域,预览的时候垂直溢出滚动,tabbar预览的时候在底部,即时设计实现
  • 中医舌象检测和识别2:基于深度学习YOLO26神经网络实现中医舌象检测和识别(含训练代码和数据集)
  • QKeyMapper:5分钟掌握Windows按键映射神器,游戏办公效率翻倍

日新闻

  • ENVI5.3.1实战:基于Landsat 8影像的区域无缝镶嵌与精准裁剪
  • 3步完成HS2-HF Patch安装:新手快速打造完美HoneySelect2体验
  • 微信好友检测终极指南:3分钟发现谁已悄悄删除你

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号