Linux进程管理、进程创建、线程实现、僵尸进程

Linux多线程基础(2):僵尸线程和资源回收 阅读详情

目录

概述

在 Linux 系统中,通过复制一个现有的进程来创建一个全新的进程。调用 fork() 的进程称为父进程,新产生的进程称为子进程。调用结束时,在返回点这个相同位置上,父进程恢复执行,子进程开始执行。fork() 系统调用从内核返回两次:一次回到父进程,另一次回到新产生的子进程。

通常,创建新的进程都是为了执行不同的程序,接着调用exec()这组函数就可创建新地址空间,并将新程序载入其中。fork()底层是由clone()系统调用实现的。

最终,通过 exit() 系统调用推出执行,这个函数终结进程并释放资源。父进程可通过 wait4() 系统调用查询子进程是否终结(这使得父进程拥有等待特定进程的能力)。进程退出设置为僵死状态,直到其父进程调用 wait() 或 waitpid() 为止。

进程描述符及任务结构

每个进程都是一个 task_struct 结构体,内核使用双向链表 task_list 来存储。task_struct 包含的数据用来描述进程:打开的文件、地址空间、挂起信号、进程状态及其他信息。

分配进程描述符

Linux 通过 slab 分配器分配 task_struct,这样能达到对象复用和缓存着色(cache coloring) 的目的。slab 分配器在内核栈底创建新的结构 thread_info,该结构含指向 task_struct 的指针。
 

struct thread_info {
    struct task_struct    *task;
    struct exec_domain    *exec_domain;
    __u32                 flags;
    __u32                 status;
    __u32                 cpu;
    int                   preempt_count;
    mm_segment_t          addr_limit;
    struct restart_block  restart_block;
    void                  *sysenter_return;
    int                   uaccess_err;
};

 
效果如图:
下过

进程描述符的存放

进程描述符 pid 默认最大值被设置为 32768。
系统管理员修改可通过/proc/sys/kernel/pid_max 来提高上限。

进程状态

task_struct 的 state 域描述进程状态。进程五状态如下:

  • TASK_RUNNING:就绪或者运行态。
  • TASK_INTERRUPTIBLE: 进程被阻塞或者睡眠。条件达成或收到信号可进入运行态。
  • TASK_UNINTERRUPTIBLE:也是阻塞或者睡眠,只有条件达成响应,对信号或中断不响应。
  • __TASK_TRACED: 被其他进程跟踪的进程,如 pstrace 对调试程序跟踪。
  • __TASK_STOPPPED:停止执行。通常收到 SIGSTOP 等信号进入此状态。

 
状态转化如图:
这里写图片描述

进程家族树

所有进程都是 pid 为 1 的 init 进程后代。
task_struct 中有指向父进程 task_struct 的 parent 指针,还包含一个称为 children 的子进程链表。

进程创建

首先使用 fork() 拷贝当前进程创建一个子进程。子进程与父进程唯一区别仅为 pid,ppid 及某些资源的统计量(例如,挂起的信号)。exec() 函数负责读取可执行文件并将其载入地址空间开始运行。

写时拷贝

为避免把所有资源都复制给新进程的效率浪费,fork() 采用 copy-on-write 页实现。fork() 的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。一般情况下,进程创建后马上执行可执行文件,这种优化可避免拷贝大量根本就不会使用的数据。

fork()

fork()、vfork() 和 __clone() 库函数都通过相应参数标志调用 clone(),然后clone()调用 do_fork(),do_fork() 调用 copy_process() 函数。
该函数之中为新进程创建内核栈、task_info、task_struct,并清零 task_struct 某些成员(主要是统计信息),大多数数据依然未修改。子进程设置为 TASK_UNINTERRUPTIBLE 确保不会投入运行。分配 pid,根据传递给 clone() 的参数标志,选择拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。最后返回一个子进程的指针。

vfork()

vfork() 与 fork() 的唯一区别是不拷贝父进程的页表项。子进程作为父进程一个单独的线程在它的地址空间运行,父进程被阻塞,直到子进程退出或执行 exec()。子进程不能像地址空间写入。

线程实现

创建线程

创建线程和创建进程只是调用clone()时参数标志不一样:

    clone(CLONE_VM | CLONE_FD | CLONE_FILES | CLONE_SIGHAND, 0);

参数就是共享的资源。由上可知,线程和父进程共享虚拟空间(VM)、文件系统资源、文件描述符和信号处理程序,而fork()的实现是:

    clone(SIGCHLD, 0);

内核线程

内核线程和普通线程区别在于没有独立的地址空间,只在内核空间运行。内核进程和普通进程一样,可以被调度,也可以被抢占。

进程终结

由 do_exit() 函数负责。进程终结会设置相关 task_struct 成员,删除相关内核定时器,输出记账信息,释放其地址空间(如果没有共享),减少相关资源引用计数,调用 exit_notify() 向父进程发送信号,给自己的子进程寻找养父,养父为线程组的其他进程或为 init 进程,并把 state 设置为 EXIT_ZOMBIE 状态。do_exit()函数再调用 schedule() 切换到新的进程,而自己成为僵尸进程不会再被调度,所以这是进程执行的最后一段代码。do_exit() 永不返回。至此进程占用的内存仅剩内核栈、thread_info 结构和 task_struct 结构。此时进程还存在的唯一目的就是向其父进程提供信息,父进程检索到信息后,或者通知内核那是无关的信息后,内核释放进程剩余内存。

删除进程描述符

在调用 do_exit() 后,尽管进程成为僵尸进程,但是系统还保留了它的进程描述符。这样可让系统有办法在该进程终结后仍能获得它的信息。因此,进程终结时所需的清理工作和进程描述符的删除分开执行。在该进程的父进程获知该进程的信息后,或者父进程通知内核它并不关注那些信息后,它的子进程(当前僵尸进程)的 task_struct 结构被释放。

如何处理僵尸进程

1.使用父进程调用 wait() 或 waitpid() 函数等待子进程,父进程阻塞。

2.异步方式,安装 signal_handler,捕获SIGCHILD信号,在信号处理函数中调用wait()函数等待。但是由于信号不支持排队,为避免信号高发时丢失信号,在处理函数中应使用 waitpid() 函数的非阻塞版本,循环对每一个子进程进行 wait 处理。方法如下:

    while(pid = waitpid(-1, &status, WNOHANG)) > 0){
        //printf("child %d exit\n", pid);
    }

参数设置为-1是因为:

-1 meaning wait for any child process.
WNOHANG 则是非阻塞模式标志。

3.直接使用 sigaction 结构体,当中的选项设置 SA_NOCLDWAIT,这样就不需要任何处理,告诉内核直接终结子进程,不要进入僵尸状态。

    struct sigaction act;
    act.sa_flags = SA_NOCLDWAIT;
    sigaction(SIGCHLD, &act, NULL);
Linux fork函数与父子进程管理深度解析 进程管理是操作系统核心功能之一,其中fork系统调用作为Linux创建新进程的基础机制,采用写时复制(COW)技术实现高效内存管理。理解父子进程间的资源共享与隔离机制,对开发守护进程、并行计算等场景至关重要。通过合理使用waitpid和信号处理,可以避免僵尸进程问题。现代Linux系统中,fork与exec的组合提供了灵活的进程控制能力,而进程池等优化技术能显著提升大规模进程创建的效率。掌握这些知识有助于构建健壮的服务器架构和资源敏感的应用程序。 阅读详情

相关推荐

从“头歌”实验到操作系统内核:进程、内存与文件系统的核心原理与实践

操作系统是计算机系统的核心,负责管理硬件资源并为应用程序提供运行环境。其核心原理包括进程管理、内存管理和文件系统。进程管理涉及进程的创建、调度与同步,是理解并发编程的基础;内存管理通过虚拟内存机制实现地址空间的隔离与高效利用;文件系统则负责数据的持久化存储与组织。这些机制共同支撑了现代计算的高性能与可靠性,在服务器部署、云计算和数据库管理等工程实践中至关重要。本文以“头歌操作系统”实验为切入点,深入探讨进程创建(如fork/exec)、内存分配及文件操作等核心概念,帮助读者解决“程序无法运行”及“虚拟机CP

weixin_33883104的博客 283

操作系统之进程和线程(僵尸进程、孤儿进程、守护进程、Linux常见命令)

1. 僵尸进程 ① 僵尸进程概述 什么是僵尸进程? 在Linux系统中,任何一个子进程在调用exit()函数结束运行后,内核会释放该进程的所有资源,包括占用的内存和打开的文件等。 同时,也会留下一个叫做僵尸进程(Zombie)的数据结构,Zombie中存储了该进程的进程号、退出码、退出状态、使用的CPU时间等信息。即僵尸进程是早已死亡的子进程,但在进程表中占了一个位置(slot)。 子进程还会向父进程发送SIGCHLD信号,父进程调用wait()或者waitpid()函数可以将僵尸进程释放(为它收尸)。 父

modi000的博客 1213

Linux内核学习之三--进程管理

进程/线程的概念 进程:包含代码段,其他资源,内存地址空间和多个执行线程。是处于执行期的程序以及相关资源的总称 线程:进程中活动的对象 进程提供两种虚拟机制: 虚拟处理器:实际为多个进程共享一个处理器,虚拟成每个进程独享一个处理器,第四章介绍 虚拟内存:让进程认为自己拥有整个地址空间,线程之间共享虚拟内存。十二章介绍 操作新进程 创建:linux中的系统调用函数:fork(),复制一个现有进程来创...

文艺小少年的博客 330

僵尸线程

转载 僵尸线程 <span style="word-wrap:break-word; font-siz pthread_join():使一个线程等待另一个线程结束 pthread_self():获得自身的线程号 pthread_create():创建一个新的线程 pthread_detach():设置线程为可分离状态,pthread有两种状态joinable状态和unjoinable状态 pthread_exit():通过自身来结束线程,并释放资源 pthread_cancel

heibai110的博客 2264

Linux内核--进程管理(一)进程的概念控制单元

本章开始,我们进入linux五大子系统之一的进程管理,本篇文章主要介绍进程的生命周期于内核中的控制单元

文艺小少年的博客 1111

linux中的僵尸进程

在linux系统中程序是以进程启动的。而每个进程有分子进程和父进程。当子进程被杀死。而父进程还在运行时。就形成了僵尸进程

【Linux】线程概念 && 线程控制(接口详谈)&& 僵尸线程的产生和解决

详谈线程基本概念 & Linux中线程相关的各种接口

Dooo_yh的博客 2019

gm/ID设计方法实践指南:从理论曲线到电路优化的关键步骤

本文详细介绍了gm/ID设计方法在模拟IC设计中的实践指南。该方法通过直接利用工艺模型数据,将设计焦点从盲目调整晶体管尺寸转向选择关键的gm/ID工作点,从而在先进工艺下实现功耗、增益和带宽等性能的精准权衡与优化。文章从理论曲线生成到具体电路设计步骤,提供了完整的实战流程。

pandas7gardener的博客 479

僵尸进程

  在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等.但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等),直到父进程通过wait / waitpid来取时才释放,此时该进程...

weixin_33755557的博客 307

双目视觉三维重构(一)————简介

优快云中关于立三维重构的介绍层出不穷,CNKI中也有各类综述对三维重构进行总结,撰写这篇博客仅作为本人对该类博客、论文的总结学习,加深自身学习的印象、作为学习的笔记。如有错误的地方,欢迎指正。   1、三维重构 1.1、三维重构到底是什么?   首先要了解立体匹配算法,首先要知道立体匹配算法主要具体应用于什么方向。 三维重构又被称为三维重建,百度百科中对它的定义为:指对三维物体建立适合...

qq_39634612的博客 1万+

Android蓝牙开发—经典蓝牙和BLE(低功耗)蓝牙的区别

      最近在做蓝牙开发,刚接触时傻傻的分不清经典蓝牙和低功耗蓝牙的区别,一直用开发低功耗蓝牙的方法去连接经典蓝牙设备,最后当然是一直连接不上了。在此记录下经典蓝牙和低功耗蓝牙的区别和联系。 Android中的蓝牙         说到Android中的蓝牙,大家听到的可能有蓝牙1.0、蓝牙2.0、蓝牙3.0、蓝牙4.0之类的以数字结尾的蓝牙版本号,而实际上,在最新的标准中,已经不再使用数...

zqf_888的博客 4万+

Linux内核学习笔记(四)进程管理

进程简介 进程(Process)是Unix操作系统最基本的抽象概念之一。进程是正在执行的程序,同时也是操作系统进行资源管理的最小单位,进程需要管理打开的文件、挂起的信号、内核内部数据、处理器状态等。 线程(Thread)是进程中正在执行的程序片段,是操作系统进行调度的最小单位,一个线程指的是进程中一个单一顺序的控制流。Linux中线程只是一个特殊的进程,并没有对进程和线程进行专门的区分。 进...

胡LiuJia@BLOG 2740

Ubuntu安装pytorch3d的最便捷方法【原创】

Ubuntu安装pytorch3d的最便捷方法

qq_54900679的博客 2924

Linux内核设计与实现(3)第三章:进程管理

Linux内核设计与实现(3)第三章:进程管理 1.进程是资源封装的单位 进程封装的资源包括:内存、文件、文件系统、信号、控制台,寄存器堆栈等。 一个进程区别于另外一个进程的标记就是占有的资源完全不一样。 2.进程提供两种虚拟机制:虚拟处理器和虚拟内存 这两种虚拟给进程造成一个假象——只有自己独享处理器以及独享真个内存资源。 有趣的是,同一进程中的线程可以共享虚拟内存,但每个都拥有各自的虚拟处理器。 虚拟处理器 ??? 3.僵尸进程 & 孤儿进程 进程退出执行后被设置为僵死状态,直到其父进程调用wa

哈尼的博客 428

PCB过孔电流承载解析:完整指南与数据参考

深入解析PCB过孔的电流承载能力,结合实际应用场景提供可靠设计参考。涵盖影响载流的关键因素,并整理实用的pcb过孔与电流对照一览表,帮助工程师优化布局与布线。

weixin_35677363的博客 632

学习笔记( 11 ) - 解决:finalshell连接虚拟机(ubuntu)超时,主机ping不通虚拟机,主机没有VMnet8网卡, Connection refused: connect

解决:finalshell连接虚拟机(ubuntu)超时,主机ping不通虚拟机,主机没有VMnet8网卡, Connection refused: connect

烟溪彭于晏的博客 2万+

linux进程管理

进程管理 1、 进程描述符和task结构体 内核把进程列表存储在一个双向循环链表中 task list;task list中的每个元素都是struct task_struct的一个进程描述符,defined in <linux/sched.h>;进程描述符包含了进程的所有信息;32bit的机器中,struct task_struct有1.7k bytes;进程描述符中包含的数据:打开...

qq_39204702的博客 357

CodeX 登录报错 os error 10013?一键修复 CodeX 无法登录问题(亲测有效)

CodeX 登录时报 os error 10013?本文提供快速修复方案,实测有效,彻底解决登录报错:登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013)的问题💡

XiaoqiangClub的博客 2927

进程管理学习笔记

进程线程学习笔记

BigGhostCell的博客 209

OpenCV 实战篇——如何测算出任一副图片中的物体的实际尺寸?传感器尺寸与像元尺寸的关系?

本文介绍了通过相机图像测算物体实际尺寸的方法,重点分析了传感器参数与成像质量的关系。文章首先给出了物体实际尺寸的计算公式,涉及像素尺寸、距离、分辨率等参数。然后详细解析了传感器尺寸与像元尺寸的关系,指出相同分辨率下更大的传感器能获得更好的成像质量。此外还介绍了光学尺寸、像素尺寸对成像的影响,以及帧率的概念。最后提及了相机标定的重要性,并概述了从像素坐标系转换到世界坐标系的基本思路。这些知识为通过相机图像进行精确测量提供了理论基础。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1336

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Linux进程控制:fork、exec与wait机制详解

进程控制是操作系统核心功能,涉及进程创建、执行与回收的全生命周期管理。通过fork()系统调用创建子进程时,会复制父进程的地址空间形成独立执行单元,而exec()系列函数则实现进程映像的完全替换,这是Shell命令执行的基础原理。wait()机制通过监控子进程状态,既能获取程序执行结果,又能避免僵尸进程导致的资源泄漏。在Linux系统编程实践中,经典的fork-exec-wait组合模式广泛应用于Shell实现、服务端进程管理等场景,理解父子进程间的资源继承关系与同步机制,对开发高可靠性的多进程应用至关重要

weixin_30896825的博客 316

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

进程与线程

练习:创建一个进程的两个子进程,子进程中打印自己的PID和父进程的PID,父进程中打印自。让父进程先结束,子进程称为孤儿进程,被init进程收养,子进程结束,init进程回收子。5. 停止态(T):由于系统需要让进程任务暂停,则将进程设置为停止态。子进程结束,父进程回收子进程空间,就能避免子进程称为僵尸进程。6. 僵尸态(Z):进程代码执行结束,空间没有被回收。7. 结束态(X):代码执行结束,空间被回收的时刻。进程代码执行结束,空间没有被回收,就会成为僵尸进程。

tj2850的博客 166

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【Linux】Linux进程管理

Linux进程管理

Linux小白一只~正处于学习阶段,觉得我写的还好的请多多给我点赞呀,谢谢大家!!(๑>ڡ<)☆ 5213

Linux 进程管理

用fork()创建子进程,利用写时复制节省资源;子进程通过exit_exit正常退出,或被信号异常终止;父进程必须通过waitwaitpid回收子进程,避免僵尸进程;孤儿进程由系统接管,无需额外处理。

scholarzjh的博客 2687
上一篇: linux内存管理--用户空间和内核空间
下一篇: Linux进程调度内核实现分析
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值