news 2026/5/9 5:14:49

【Linux】进程控制(一):进程的创建和终止

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Linux】进程控制(一):进程的创建和终止

一、进程创建

1.1 fork函数初识

  • 在进程概念(一)中已经讲解大部分fork知识

在Linux中fork是一个非常重要的函数,它从已存在的进程中创建一个新的进程 。新的进程为子进程,而原来的进程为父进程。

代码语言:javascript

AI代码解释

#include <unistd.h>//包含的头文件 pid_t fork(void); 返回值:子进程中返回0,⽗进程返回⼦进程id,出错返回-1

在这里插入图片描述

总而言之: 进程调用fork,当控制转移到内核中的fork代码后,内核做: • 分配新的内存块和内核数据节后给子进程 • 将父进程部分数据结构内容拷贝到子进程中 • 添加子进程到系统进程列表当中 • fork返回,开始调度器调度

我们来看一段代码:

代码语言:javascript

AI代码解释

#include <stdlib.h> #include <stdio.h> #include <unistd.h> int main( void ) { pid_t pid; printf("Before: pid is %d\n", getpid()); if ((pid=fork()) == -1 ) { perror("fork()"); exit(1); } printf("After:pid is %d, fork return %d\n", getpid(), pid); sleep(1); return 0;

运行结果:

  1. 这⾥看到了三行输出,⼀行before,两行after。进程5431先打印before消息,然后它又打印after。
  2. 另⼀个after由5432打印的。注意到进程5432没有打印before,为什么呢?如下图所⽰

结论:所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。


1.2 fork函数返回值

我们先说结论:子进程返回0,父进程返回子进程的pid所以我们可以利用这个结论来让父进程和子进程执行不同的执行流(代码块)

观察如下代码:

代码语言:javascript

AI代码解释

#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { printf("i am parent,pid: %d, ppid %d\n\n", getpid(), getppid()); pid_t id = fork(); if(id == 0) { while(1) { printf("i am child,pid: %d, ppid %d\n", getpid(), getppid()); sleep(1); } } else if(id > 0) { while(1) { printf("i am parent,pid: %d, ppid %d\n", getpid(), getppid()); sleep(1); } } else { peeor("fork()"); exit(1); } return 0; }

运行结果如下:

在这里插入图片描述

1.3 写时拷贝

关于写实拷贝,我们有在进程概念(六)中简单提到过:【点击进入】

  • 我们通过下面这张图更加深入的了解写时拷贝

在这里插入图片描述

写时拷贝是操作系统为优化进程创建而设计的内存管理策略。当父进程创建子进程时,操作系统并不立即复制父进程的数据段,而是让父子进程共享同一物理内存页,仅将相关页表项标记为只读权限。

  1. 数据结构继承:子进程的内核数据结构完全以父进程为模板,包括:
    • 进程控制块(task_struct)
    • 内存描述符(mm_struct)
    • 页表结构
  2. 权限设置
    • 代码段:保持只读权限(代码本身不应修改)
    • 数据段:原本可读写的页被强制设置为只读权限,为写时拷贝做准备
  3. 当任一进程尝试修改共享数据时:
    • 访问异常:CPU检测到对只读页的写操作,触发页保护异常
    • 异常转换:操作系统识别此为写时拷贝场景,将异常转换为缺页中断
    • 内存分配内核分配新的物理内存页
    • 数据拷贝将原页内容复制到新页
    • 权限更新更新页表项,指向新物理页并恢复可读写权限

因为有写时拷贝技术的存在,所以父子进程得以彻底分离离!完成了进程独立性的技术保证! 写时拷贝是⼀种延时申请技术,可以提高整机内存的使用率。


1.4 fork常规用法

  1. 一个进程希望复制自己,使子进程同时执行不同的代码段。例如父进程等待客户端请求,生成子进程来处理请求。
  2. 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

1.5 for调用失败的原因

fork函数创建子进程也可能会失败,有以下两种情况:

  1. 系统中有太多的进程,内存空间不足,子进程创建失败。
  2. 实际用户的进程数超过了限制,子进程创建失败。

二、进程终止

2.1 进程退出场景

  1. 代码运行完毕,结果正确
  2. 代码运行完毕,结果错误
  3. 代码异常终止
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 6:02:34

基于SpringBoot+Vue的Spring Boot疗养院管理系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】

系统架构设计### 摘要 随着人口老龄化趋势加剧&#xff0c;疗养院管理系统的需求日益增长。传统疗养院管理模式依赖人工操作&#xff0c;存在效率低、数据易丢失、信息共享困难等问题&#xff0c;难以满足现代疗养院的运营需求。数字化管理系统能够有效提升疗养院的服务质量和…

作者头像 李华
网站建设 2026/5/8 3:33:45

计算机是如何运作的?看看汇编语言吧

一、寄存器 寄存器是中央处理器&#xff08;CPU&#xff09;内部集成的一组高速、小型的存储单元&#xff0c;其容量通常仅为几个字节&#xff08;如8位、16位、32位或64位&#xff09;&#xff0c;但访问速度远高于主内存&#xff08;RAM&#xff09;甚至高速缓存&#xff08…

作者头像 李华
网站建设 2026/4/27 7:37:00

【Java 笔记】面向对象核心 - 内存图

核心总结Java 三种场景内存图的核心逻辑&#xff1a;内存分区&#xff1a;栈存局部变量 / 对象引用&#xff08;地址&#xff09;&#xff0c;堆存对象及成员变量&#xff0c;方法区存类信息&#xff1b;单个对象&#xff1a;栈中引用指向堆中唯一对象&#xff0c;通过地址操作…

作者头像 李华
网站建设 2026/5/1 9:45:03

企业级经方药食两用服务平台管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

摘要 随着中医药文化的全球推广和健康理念的普及&#xff0c;药食两用产品的市场需求显著增长。传统的中药企业及健康管理平台在信息化管理方面仍存在效率低下、数据孤岛等问题&#xff0c;亟需一套高效、智能的管理系统实现资源整合与流程优化。企业级经方药食两用服务平台旨…

作者头像 李华