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

从源码入手,详解Linux进程

概念

进程 = PCB + 对应的代码和数据

PCB:Process Control Block【进程控制块】
在Linux中是:task_struct,本质是结构体组成的链表

PCB与对应的代码和数据都存储在内存中,但是CPU会通过OS直接操作PCB,间接控制上层代码/数据的运行及处理等。由于PCB的本质是链表,因此OS控制进程的方式实际是对链表进行增、删、查、改操作。

Task_struct

C语言中,结构体是由一个或多个成员变量组成的自定义类型。换句话说,这些成员变量是结构体所具有的不同属性。
Linux内核中的PCB实际就是一个结构体,被成为Task_struct。Task_struct中的成员变量即为线程所具有的属性。

以下摘自0.11版本Linux内核源码

// 任务(进程)数据结构struct task_struct {/* these are hardcoded - don't touch */long state; /* -1 unrunnable, 0 runnable, >0 stopped */         // 任务的运行状态(-1 不可运行,0 可运行(就绪),>0 已停止)long counter;    //counter 值的计算方式为 counter = counter /2 + priority,  优先执行counter最大的任务;  任务运行时间计数(递减)(滴答数)(时间片)long priority;      // 运行优先数。任务开始运行时 counter = priority,越大运行越长long signal;        // 信号。是位图,每个比特位代表一种信号,信号值=位偏移值+1struct sigaction sigaction[32];     // 信号执行属性结构,对应信号将要执行的操作和标志信息long blocked;   /* bitmap of masked signals */  // 进程信号屏蔽码(对应信号位图)
/* various fields */int exit_code;                                                  //任务执行停止的退出码,其父进程会取unsigned long start_code,end_code,end_data,brk,start_stack;     // 代码段地址,代码长度,数据长度,总长度,栈段地址long pid,father,pgrp,session,leader;                            // 进程标识号,父进程号,父进程组号,会话号,会话首领unsigned short uid,euid,suid;                                   // 用户标识号, 有效用户id,保存的用户idunsigned short gid,egid,sgid;                                   // 组标识号,有效组号,保存的组号long alarm;                                                     // 报警定时器值long utime,stime,cutime,cstime,start_time;                      // 用户态运行时间,系统态运行时间,子进程用户态运行时间,子进程系统态运行时间,进程开始运行时刻unsigned short used_math;                                       // 是否使用了协处理器
/* file system info */int tty;        /* -1 if no tty, so it must be signed */    // 进程使用 tty 的子设备号。-1 表示没有使用unsigned short umask;                                       // 文件创建属性屏蔽位struct m_inode * pwd;                                       // 当前工作目录i节点struct m_inode * root;                                      // 跟目录i节点struct m_inode * executable;                                // 执行文件i节点unsigned long close_on_exec;                                // 执行时关闭文件句柄位图标志struct file * filp[NR_OPEN];                                // 进程使用的文件表结构,用于保存文件句柄
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */struct desc_struct ldt[3];                                      // 局部描述符段, 0-空,1-代码段 cs,2-数据和堆栈段 ds&ss
/* tss for this task */struct tss_struct tss;                                      // 本进程的任务状态段信息结构
};

比较重要的变量:

  • 与信号相关的两个变量signalblocked,即分别为信号待决表,信号屏蔽表。
  • exit_code进程退出
  • start_code,end_code,end_data,brk,start_stack为虚拟地址空间不同段的起始标识。
  • pid进程号
  • umask文件创建时的权限屏蔽字

对进程进行操作

在C语言中,用户可以调用对应的函数对进程进行操作。
进程有其自己的类型pid_t,大部分与相关的函数的返回值类型都是pid_t类型。

getpid() & getppid()

调用这两个函数分别可以获得当前进程的id,及其父进程的id.
使用时需要包含头文件

#include <sys/types.h>
#include <unistd.h>

getpid() returns the process ID (PID) of the calling process. (This is often used by routines that generate unique temporary filenames.)

getppid() returns the process ID of the parent of the calling process. This will be either the ID of the process that created this process using fork(), or, if that process has already terminated, the ID of the process to which this process has been reparented (either init(1) or a “subreaper” process defined via the prctl(2) PR_SET_CHILD_SUBREAPER operation).

wait() & waitpid()

二者都是系统调用,父进程使用,目的是等待子进程运行完毕,接收返回信息。
在多进程任务中,等待子进程调用结束是必须的,因为需要防止僵尸进程的出现,父进程需要及时回收子进程开辟的空间。详见工作手册↓

$ man wait

wait()

函数原型:: pid_t wait(int *wstatus);
wait()与waitpid(),二者略有不同,简单来说,wait()的功能简单直接:等待当前父进程创建的所有子进程,直到其中一个子进程退出为止。在实际运用中不常使用。

返回值:: 成功等待则返回结束子进程的id,否则返回-1.

RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.

waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state, then 0 is returned. On error, -1 is returned.

waitpid()

函数原型:: pid_t waitpid(pid_t pid, int *wstatus, int options);
参数pid的取值范围为[-inf, inf],具体有不同的含义:

< -1 meaning wait for any child process whose process group ID is equal to the absolute value of pid.

-1 meaning wait for any child process.

0 meaning wait for any child process whose process group ID is equal to that of the calling process at the time of the call to waitpid().

>0 meaning wait for the child whose process ID is equal to the value of pid.

当参数选择<-1时,等待进程组ID为参数绝对值的任一子进程。
当参数选择-1时,其效果与wait()相同。
当参数选择0时,等待与父进程所在进程组的任一子进程。
当参数选择>0时,则相当于指定等待该进程号的进程。

若指定等待成功则返回0,否则返回-1.

如果想实际进行进程调度的实操,可以参阅另一篇博客从零开始实现Shell | Linux进程调度实战

http://www.xdnf.cn/news/19928.html

相关文章:

  • 并发编程指南 同步操作与强制排序
  • 理解Go与Python中的闭包(Closure)
  • 充电枪结构-常规特征设计
  • 代码随想录刷题Day48
  • PostgreSQL 索引使用分析2
  • 权威认证!华宇TAS应用中间件获得商用密码产品认证证书
  • 深入解析Go语言切片(Slice)精髓
  • 【论文阅读】LightThinker: Thinking Step-by-Step Compression (EMNLP 2025)
  • 金额字段该怎么设计?——给小白的超详细指南(含示例 SQL)
  • UniApp 混合开发:Plus API 从基础到7大核心场景实战的完整指南
  • 一文吃透 Protobuf “Editions” 模式从概念、语法到迁移与实战
  • 自动化仓库托盘搬运减少错误和损坏的方法有哪些?实操案例解读
  • 【踩坑记录】Unity 项目中 PlasticSCM 掩蔽列表引发的 文件缺失问题排查与解决
  • 分割回文串手绘图
  • 【OpenGL】LearnOpenGL学习笔记19 - 几何着色器 Geometry Shader
  • 解决 Android Studio 中 build 目录已被 Git 跟踪后的忽略问题
  • 【stm32】定时器中断与定时器外部时钟
  • el-table 行高亮,点击行改变背景
  • CVE-2025-6507(CVSS 9.8):H2O-3严重漏洞威胁机器学习安全
  • 安全测试漫谈:如何利用X-Forwarded-For头进行IP欺骗与防护
  • TDengine NOW() 函数用户使用手册
  • Ubuntu环境下的 RabbitMQ 安装与配置详细教程
  • RabbitMQ篇
  • 20250903的学习笔记
  • LangChain实战(十三):Agent Types详解与选择策略
  • 动态IP和静态IP配置上有什么区别
  • 单片机控制两只直流电机正反转C语言
  • 如何保存训练的最优模型和使用最优模型文件
  • 【wpf】WPF开发避坑指南:单例模式中依赖注入导致XAML设计器崩溃的解决方案
  • SpringBoot注解生效原理分析