内核篇第一讲: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是两份独立副本,修改互不干扰。

相关推荐
AR-26710-5 小时前
Linux Day16——日志
linux·运维
小HANN5 小时前
华为云企业网站上云实战|从零搭建高可用WordPress(ECS+RDS+ELB+弹性伸缩+云监控全流程落地)
linux·运维·服务器·经验分享
susplus6 小时前
【IMX6ULL Linux系统移植】SD卡分区 | uboot详解
linux·arm·u-boot
@三十一Y6 小时前
Linux:实现简易的shell
linux
2301_777998347 小时前
TCP连接断开:进程终止、主机断电与网络断开
linux·服务器·网络·tcp/ip
星恒随风7 小时前
Linux进程基础(二):进程调度、上下文切换、O(1)调度器、环境变量与虚拟地址空间
linux·笔记·学习·状态模式
xbzb8 小时前
一边装一边报错:CentOS 7 + LNMP 跑 ECShop 的常见故障与解法
linux·运维·centos
学linux的QQ蛋8 小时前
图解 Linux 驱动编译进内核的完整工作流程
linux·运维·服务器
承渊政道8 小时前
Linux网络学习【UDP Socket编程实战:网络命令与客户端访问Linux验证】
linux·网络·学习·ubuntu·编程实战·udp socket
程序员-Benothing8 小时前
正则表达式详解:BRE、ERE、PCRE语法与实战案例
linux·运维·服务器