一篇文章看懂 Linux 进程的创建、中止、等待与替换

📚 一篇文章看懂 Linux 进程的创建、中止、等待与替换

全程大白话 + 易懂代码示例


一、什么是 Linux 进程?

进程(Process)简单来说就是 “正在运行的程序”。比如你用浏览器打开这个网页时,浏览器就是一个进程。

  • 进程就像程序的活动分身,每个进程有独立的代码、内存空间、运行状态(PID唯一编号)。

二、进程的创建:fork()

想要创建新进程?用 fork():像细胞分裂一样,复制自己!

代码示例

#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();  // 分裂出一个子进程

    if (pid == 0) {
        // 子进程执行的代码
        printf("我是子进程,我的PID是%d,爸爸是%d\n", getpid(), getppid());
    } else if (pid > 0) {
        // 父进程执行的代码
        printf("我是父进程,我的PID是%d,刚创建的子进程PID是%d\n", getpid(), pid);
    } else {
        perror("fork 失败啦!");
    }
    return 0;
}

关键点

  1. fork() 会复制父进程的全部内容(代码、变量、打开的文件等),但在现代系统采用“写时复制(Copy-On-Write)”优化。

  2. fork() 返回值不同

    • 父进程 返回子进程的PID(用来追踪和管理孩子)。
    • 子进程 返回0(表示自己是儿子)。
  3. 父子进程 代码完全相同,但要靠返回值区分身份(执行不同逻辑)。


三、进程的中止:exit()_exit()

想让进程结束?两个选择:💣

  • exit(int status):
    完美退场!会做 清理工作(刷新缓冲区、关闭文件)。
  • _exit(int status):
    火速下线!直接终止进程,不做任何清理。

代码示例

#include <stdlib.h> // 用于exit
#include <unistd.h> // 用于_exit

void child_process() {
    printf("子进程:先打印这句话……\n");
    exit(0);               // 输出正常显示
    // _exit(0);          // 可能不输出上一句(如果缓冲区没刷新)
}

四、进程的等待:wait()waitpid()

当父进程需要 等待子进程结束(有些像等孩子放学),否则会产生“僵尸进程”(已结束但未被回收,占用系统资源)。

wait() 示例

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

int main() {
    pid_t pid = fork();
    if (pid == 0) {
        printf("子进程工作中...\n");
        sleep(2);
        exit(10);
    } else {
        int status;
        wait(&status); // 等待子进程结束
        printf("子进程退出了,状态码是 %d\n", WEXITSTATUS(status));
    }
    return 0;
}

关键函数

  1. wait(int\* status):
    阻塞父进程,直到 任意一个子进程退出
  2. waitpid(pid_t pid, int\* status, int options):
    更灵活!可以指定等待某个子进程(pid参数),或设置非阻塞模式(options=WNOHANG)。

五、进程的替换:exec 家族

想让子进程 执行一个全新的程序?用 exec 系列函数!

  • exec替换当前进程的代码段,但PID不变(还是原来那个“身体”,但灵魂已变)。

常用函数

函数名特点
execl("程序路径", args..., NULL)参数用逗号分隔,参数列表以NULL结尾
execv("程序路径", args数组)参数通过数组传递
execvp自动在PATH环境变量中查找程序

代码示例

#include <unistd.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程替换为执行 "ls -l" 命令
        execlp("/bin/ls", "ls", "-l", NULL);
        // 如果execl执行成功,后续代码不会执行
        perror("替换失败!"); 
        exit(1);
    } else {
        wait(NULL); // 等待子进程完成
    }
    return 0;
}

🚨 注意事项 (避坑指南!)
  1. fork 后务必判断返回值,父子进程逻辑需分开写。
  2. 避免僵尸进程:父进程必须使用 wait/waitpid 回收子进程。
  3. exec 替换后原进程代码无效,不要在exec后写其他代码。
  4. 多进程共享文件描述符:fork会把父进程打开的文件复制给子进程,注意关闭不需要的文件。

🌟 总结
  • 创建fork() 复制出子进程,父子身份由返回值区分。
  • 中止:正常退出用 exit,紧急退出用 _exit
  • 等待:父进程需 wait 回收子进程,防止僵尸。
  • 替换exec 让进程“变身”,运行新程序。

试着用上面的代码跑起来,并观察输出,理解每个步骤发生了什么!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值