内核篇第一讲:linux创建进程

大家好,接下来的一段时间我将开始学习野火的Linux 系统课程并将学习到的干货逐步更新到我的CSDN博客中。没时间刷课的同学可以把我的博客喂给AI 突击一下。

目录

一、查看进程

二、查看进程之间关系

1、常用参数

三、创建进程

[2、fork 基础介绍](#2、fork 基础介绍)

[1. 函数基础信息](#1. 函数基础信息)

[2. fork 执行流程核心结论](#2. fork 执行流程核心结论)

3、代码示例讲解

[1. 示例源码](#1. 示例源码)

[2. 程序运行输出](#2. 程序运行输出)

[3. 逐行执行拆解](#3. 逐行执行拆解)

[4. 高频坑点](#4. 高频坑点)

一、查看进程

复制代码
#查看系统全部进程并分页展示:

ps -ef | more
  • ps -ef

    • ps:查看系统进程快照
    • -e:显示所有进程(全部用户的进程)
    • -f:完整格式输出(UID、PID、PPID、CMD 等详细信息) 作用:列出系统全部进程的详细信息。
  • | 管道符 把左边命令ps -ef标准输出 ,直接当作右边命令more标准输入

  • more 分页查看工具。当输出内容太长、一屏放不下时,一页一页显示

    • 回车:下一行
    • 空格:下一页
    • q:退出

二、查看进程之间关系

pstree:以树状结构打印进程父子关系 ,直观看到父进程、子进程的派生链条,比ps -ef看 PPID 更直观。

Linux 内核中所有进程起源于systemd(老系统是 init,PID=1)。

1、常用参数

  • pstree:默认,只显示进程名,精简树形
  • pstree -p同时显示 PID 号(最常用,面试 / 调试必用)
  • pstree -u:显示进程所属用户
  • pstree -ap:显示 PID + 完整命令行

三、创建进程

2、fork 基础介绍

1. 函数基础信息

头文件:#include <unistd.h>

函数原型:pid_t fork(void);

pid_t:是进程 ID 类型,本质是整型,专门存放 PID。

返回值:

执行结果 进程类型 返回值含义
创建成功 父进程(原进程) 返回正整数,该数字就是新建子进程的 PID
创建成功 子进程(新建进程) 返回 0
创建失败 父进程(无子进程产生) 返回 -1,失败原因:内存不足、系统进程数量达到上限

2. fork 执行流程核心结论

  1. fork 之前 :操作系统只有1 个父进程 ,fork 前面的代码只会执行 1 次
  2. fork 之后 :操作系统存在两个几乎完全相同的进程(父 + 子) ,fork后面 的代码,父子进程各自执行一遍,一共执行 2 次

子进程会拷贝父进程的内存空间、变量、文件描述符、程序计数器;现代 Linux 采用写时复制 COW :刚 fork 时父子共享同一份物理内存,只有任意进程修改数据时,内核才单独复制内存页面,节省开销。 父子进程是完全独立的进程,变量互相隔离,互不影响;CPU 调度器随机决定父子谁先运行,顺序不固定。


3、代码示例讲解

1. 示例源码

复制代码
#include <unistd.h>
#include <stdio.h>

int main()
{
    pid_t i;
    printf("before fork!\r\n");  // fork【之前】代码,仅父进程执行
    i = fork();                  // 在此处分裂,产生子进程
    printf("after fork:i=%d\r\n",i); // fork【之后】代码,父子各跑一次
    return 0;
}

2. 程序运行输出

复制代码
before fork!
after fork:i=28108
after fork:i=0

3. 逐行执行拆解

  1. 程序启动,只有父进程,执行到printf("before fork!\r\n"); 因为带\n换行符,刷新 stdout 缓冲区,打印一行before fork!只打印一次)。
  2. 执行 i = fork();
    • 内核创建子进程,复制父进程上下文,两个进程都停在 fork 返回位置。
    • 父进程 :变量i = 28108(28108 就是子进程 PID)
    • 子进程 :变量i = 0
  3. 父子两个进程并行继续执行 fork 之后的代码:
    • 父进程执行printf("after fork:i=28108\r\n",i); → 输出after fork:i=28108
    • 子进程执行printf("after fork:i=0\r\n",i); → 输出after fork:i=0

4. 高频坑点

  • 缓冲区陷阱: 如果printf("before fork!");不加换行\n ,会打印两次before fork!。 原因:printf 输出保存在用户缓冲区,没有刷新;fork 拷贝内存的时候,连同缓冲区里未输出的字符串一起复制。父子进程退出时,各自刷新缓冲区,就输出两遍。

\n的作用:刷新标准输出缓冲区。

  • 父子执行顺序不确定 谁先打印由操作系统调度器决定,不一定父进程一定优先输出。

  • 父子进程变量相互独立 父的i和子的i是两份独立副本,修改互不干扰。

相关推荐
吴声子夜歌1 小时前
Shell编程实例——bash的配置与自定义(二)
linux·运维·shell
风笙9781 小时前
[内存管理] page数据结构
linux
Awh-1 小时前
ARM 裸机开发 day02 学习笔记
linux·arm开发·arm
牢姐与蒯2 小时前
Linux进程间通信(一).进程间通信概念&&环境切换(着重强调vscode)
linux·运维·服务器·ubuntu
M78佐菲2 小时前
ARM学习笔记(四)
linux·arm开发·笔记·嵌入式硬件·学习
东鹏特饮2 小时前
redhat9 配置yum 阿里云
linux·运维·redhat·yum
昌原的儿子LEO2 小时前
i.MX6ULL 裸机开发 C 语言驱动与 BSP 工程管理学习总结
linux·arm开发·学习
lqg_zone2 小时前
CentOS 7 虚拟机磁盘 I/O 卡顿排查实录:从 iostat 异常到虚拟盘后端故障的完整定位
linux·服务器·mysql·centos
kkkkkkkkkk_Z2 小时前
单片机|学习日记:单片机底层架构与寄存器操作全解析
linux·笔记·单片机·学习·51单片机