Linux的进程管理

2023-11-12

目录

1、概述

2、进程描述符

2.1 进程描述符的分配

2.2 进程描述符的存放

2.3 进程状态

2.4 进程上下文

2.5 进程家族树

3、进程的创建

4、进程的终结

5、线程的实现


1、概述

    进程是执行期的代码。但是进程不止包括这样一段可执行的代码,还包括进程执行相关的各种资源:

  • 打开的文件;
  • 挂起的信号;
  • 内核内部的数据;
  • 处理器状态;
  • 一个或多个具有内存映射的地址空间;
  • 一个或多个执行线程;
  • 存放全局变量的数据段;
  • ......

    进程在创建它的时候开始存活,在Linux系统中,这通常的fork()系统调用的结果。fork()系统调用通过复制一个现有进程来创建一个新的进程,调用fork()的进程称为父进程,新创建的进程称为子进程。在fork()系统调用结束时,父进程恢复执行,子进程开始执行。fork()系统调用从内核返回两次:一次是回到父进程,一次是回到子进程。Linux内核中,fork()实际上是通过clone()调用实现的。

    fork()调用后,通过exec()调用可以创建新的地址空间,并把程序载入其中。最终,程序通过exit()调用退出执行,并释放其占用的资源。父进程可以通过wait4()调用等待子进程的执行结果。程序执行完成后被设置为僵死状态,直到它的父进程调用wait()或waitpid()调用。

    执行线程简称线程,是在进程中活动的对象。每个线程都有一个独立的程序计数器、进程栈和一组进程寄存器。内核调度的对象是线程而不是进程。对于Linux而言,线程就是一种特殊的进程。

2、进程描述符

    进程描述符用来描述一个具体的进程的所有信息。进程描述符的数据结构叫做task_struct,定义在<linux/sched.h>文件中。

    task_struct数据大小约为1.7KB(32位机器),包含了内核管理一个进程所需要的全部信息:

  • 进程的id(pid);
  • 打开的文件;
  • 进程的地址空间;
  • 挂起的信息;
  • 进程的状态;
  • ......

2.1 进程描述符的分配

    Linux通过slab分配器动态分配task_struct结构,分配时只需要在进程内核栈的尾端创建一个新的结构thread_info即可。其中,task域存放的是指向task_struct的指针。

2.2 进程描述符的存放

    内核通过唯一的进程标识值PID(Process Identification Value)来标识每个进程。pid的类型是隐含类型pid_t,实际上就是int。为了兼容老版本,PID数的最大值是32768(有符号short int最大值),但是可以在<linux/threads.h>中增加到400万。内核把每个进程的pid存放到进程描述符中。

    内核大部分处理进程的操作,都是通过task_struct实现的,因此内核需要能获取到指向task_struct的指针。有些内存结构有专门的寄存器存放task_struct的指针,而x86等寄存器不富裕的体系,只能在内核栈的尾端创建thread_info,通过计算内存偏移来简接查找task_struct。

2.3 进程状态

    进程描述符的state域描述了进程的状态。进程包含5种状态:

  • TASK_RUNNING:运行,进程是可执行的。可能正在执行,也可能正在任务队列等待执行。这是进程在用户空间中执行的唯一可能的状态;
  • TASK_INTERRUPTIBLE:可中断,此时的进程正在睡眠(也叫阻塞),等待某些条件的达成。处于此状态的进程会因为提前接收到信号而被唤醒;
  • TASK_UNINTERRUPTIBLE:不可中断,除了接收到信号也不会提前被唤醒,其他的和可中断相同。这个状态通常用在等待时不受干扰,或者等待的事情很快发生的场景;
  • __TASK_TRACED:被其他进程跟踪的进程,例如通过ptrace对调试进程进行跟踪;
  • __TASK_STOPPED:停止,进程停止执行,进程没有投入运行,也不能投入运行。通常这种状态发生在接收到SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU等信号时;在调试期间接受到任何信号,也会进入这个状态。

2.4 进程上下文

    当一个程序执行了系统调用,或者触发了某个异常,就陷入了内核空间,此时称内核“代表程序执行”,并处于进程上下文。除非期间有更高优先级的进程要执行,并且调度器做出了相应调整,否则在内核退出的时候,程序恢复在用户空间继续运行。

    系统调用和异常处理是对内核明确定义的接口,进程只有通过这些接口才能陷入内核,即进程对内核的所有访问都需要通过这些接口。

2.5 进程家族树

    Linux的所有进程都是PID为1的初始进程的后代。内核在系统启动的最后阶段启动init进程。该进程读取系统的初始化脚本,并执行相关的程序,最终完成系统启动的整个过程。

    系统中每个进程都有一个父进程,和零个或多个子进程。拥有同一父进程的进程,称为兄弟进程。进程间的关系存放在进程描述符中,每个task_struct都包含一个parent指针,指向父进程所在的task_struct,以及一个名为children的指针链表,指向所有的子进程的task_struct。

3、进程的创建

    Unix把进程的创建拆分成了两个函数:

  • fork():Linux通过clone()系统调用实现了fork(),通过拷贝当前进程创建一个子进程。子进程和父进程的区别只在于PID、PPID(父进程的PID)和一些统计量。
  • exec():将可执行文件载入地址空间开始执行。

    Linux的fork()使用写时拷贝(copy-on-write)页实现资源的复制。资源的复制,只有在需要写入的时候才进行,在此之前以只读方式共享。这种技术使地址空间的页拷贝推迟到实际发生写入的时候才进行,如果页根本不会被写入,例如fork()后立即执行exec(),则无需复制。这样可以避免拷贝大量根本不会被使用的数据,这也是Unix快速执行的能力的一种重要支撑。

    fork()的实际开销就是复制父进程的页表,以及给子进程创建唯一的进程描述符。进程页表是进程私有的结果,映射了内核态和用户态的线性地址。

4、进程的终结

    当一个进程终结时,内核会回收进程的全部资源,并通知父进程。

1、do_exit()方法回收资源并更新状态:

  1. 回收地址空间:如果没有其他进程占用,就释放掉地址空间;
  2. 回收文件描述符、文件系统数据:引用计数分别递减,如果减为0,就释放;
  3. 执行退出代码:执行操作系统规定的退出动作,并把退出代码存放到task_struct中的exit_code中供父进程随时检索;
  4. 设置退出状态:task_struct中的exit_state设置为EXIT_ZOMBIE,进程不再接受调度;
  5. 给子进程重新寻找父进程,新的父进程是线程组的其他线程,或者init进程;
  6. 调用schedule()方法切换到新的进程。

2、此时,进程所占有的内存资源只剩下内核栈、thread_info和task_struct。此时进程存在的唯一目的,就是向它的父进程提供信息。父进程检索到相关信息后,或者通知内核那是无关信息后,内核会释放剩下的这些资源。

5、线程的实现

    Linux内核并没有线程的概念,它把线程当做进程来实现,线程仅仅被视为与其他进程共享某些资源的进程。线程有自己的task_struct,所以从内核的角度,线程只是一个普通的进程,仅仅是和其他进程共享了一些资源,比如地址空间等。

1、线程的创建

    创建线程和创建进程相似,也是调用clone()实现,只不过传递的一些参数,用来控制共享一些资源:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)

    这些代码是用来和父进程共享:地址空间、文件系统资源、文件描述符和信号处理程序

    相对之下,创建进程的命令:

clone(SIGCHLD)

2、内核线程

    内核线程是独立运行在内核空间的标准进程,内核在后台执行操作,使用内核线程来完成。内核线程和普通进程的区别,只在于内核线程没有独立的地址空间。它们只在内核空间运行,不会切换到用户空间。内核进程和普通进程一样,可以被调度,也可以被抢占。

    内核线程只能由内核线程来创建,内核从kthreadadd内核进程衍生出新的内核进程。在Linux系统中,可以使用ps -ef命令看到很多内核线程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux的进程管理 的相关文章

  • 在Linux伪终端中执行从一个终端发送到另一个终端的字符串

    假设我有一个终端 其中 tty 的输出是 dev pts 2 我想从另一个终端向第一个终端发送命令并执行它 使用 echo ls gt dev pts 2 仅在第一个终端中打印 ls 有没有办法执行字符串 不 终端不执行命令 它们只是数据的
  • Snap-confine 具有提升的权限,并且不受限制,但应该受到限制。拒绝继续避免权限升级攻击

    我已经使用 snap 一段时间了 但最近升级后 当我尝试打开任何应用程序时 出现此错误 Snap confine has elevated permissions and is not confined but should be Refu
  • 在键盘热插拔上加载模块

    我正在尝试学习如何为 Linux 系统编写模块和驱动程序 类似于this https unix stackexchange com questions 120839 usb kernel module does not load on de
  • Bash 中 $() 和 () 之间的区别

    当我打字时ls l echo file 支架的输出 这只是简单的回显 被获取并传递到外部ls l命令 就等于简单的ls l file 当我打字时ls l echo file 我们有错误 因为不能嵌套 内部外部命令 有人可以帮助我理解之间的区
  • 使用 MongoDB docker 镜像停止虚拟机而不丢失数据

    我已经在 AWS EC2 上的虚拟机中安装了官方的 MongoDB docker 映像 并且数据库上已经有数据 如果我停止虚拟机 以节省过夜费用 我会丢失数据库中包含的所有数据吗 在这些情况下我怎样才能让它持久 有多种选择可以实现此目的 但
  • UDP 广播发送失败:在 Linux 2.6.30 上“网络无法访问”

    我用udp广播写了一个程序 代码段如下 struct sockaddr in broadcast addr socklen t sock len sizeof broadcast addr bzero broadcast addr sock
  • gdb 错误 - 文件不是可执行格式:无法识别文件格式

    我正在尝试使用 gdb 调试某个名为 xdf 的程序 但是当我运行 gdb xdf 时 出现以下错误 home nealtitusthomas X ray astronomy heasoft 6 24 x86 64 pc linux gnu
  • Xenomai 中的周期性线程实时失败

    我正在创建一个周期性线程 它在模拟输出上输出方波信号 我正在使用 Xenomai API 中的 Posix Skin 和 Analogy 我使用示波器测试了代码的实时性能 并查看了方波信号 频率为 1kHz 的延迟 我应该实现 250us
  • 使用脚本自动输入 SSH 密码

    我需要创建一个自动向 OpenSSH 输入密码的脚本ssh client 假设我需要通过 SSH 进入myname somehost用密码a1234b 我已经尝试过 bin myssh sh ssh myname somehost a123
  • 如何在 Linux x86_64 上模拟 iret

    我正在编写一个基于 Intel VT 的调试器 由于当 NMI Exiting 1 时 iret 指令在 vmx guest 中的性能发生了变化 所以我应该自己处理vmx主机中的NMI 否则 guest会出现nmi可重入错误 我查了英特尔手
  • 是否有可能在linux中找到包含特定文本的文件?

    考虑这种情况 我在文件夹 Example 下有很多文件 如果我需要找到一个包含特定短语 如 Class Example 的文件 我该如何使用 Linux shell 来做到这一点 linux中有类似 定位 的函数可以做到这一点吗 Thank
  • Linux命令列出所有可用命令和别名

    是否有一个 Linux 命令可以列出该终端会话的所有可用命令和别名 就好像您输入 a 并按下 Tab 键一样 但针对的是字母表中的每个字母 或者运行 别名 但也返回命令 为什么 我想运行以下命令并查看命令是否可用 ListAllComman
  • 在 shell 脚本中查找和替换

    是否可以使用 shell 在文件中搜索然后替换值 当我安装服务时 我希望能够在配置文件中搜索变量 然后在该值中替换 插入我自己的设置 当然 您可以使用 sed 或 awk 来完成此操作 sed 示例 sed i s Andrew James
  • 是否从页面缓存中的脏页面进行文件读取?

    当字节写入文件时 内核不会立即将这些字节写入磁盘 而是将这些字节存储在页缓存中的脏页中 回写缓存 问题是 如果在脏页刷新到磁盘之前发出文件读取 则将从缓存中的脏页提供字节 还是首先将脏页刷新到磁盘 然后进行磁盘读取以提供字节 将它们存储在进
  • 进程名称长度的最大允许限制是多少?

    进程名称允许的最大长度是多少 我正在读取进程名称 proc pid stat文件 我想知道我需要的最大缓冲区 我很确定有一个可配置的限制 但就是找不到它在哪里 根据man 2 prctl http man7 org linux man pa
  • 具有少量父设备属性的 udev 规则

    我需要复杂且通用的udev规则来确定插入任何 USB 集线器的特定端口的 USB 设备 所以 我必须结合设备树不同层的父属性 我有这个 udevadm info query all name dev ttyUSB0 attribute wa
  • 如何在 Linux 主机上的 docker 容器中挂载目录 [重复]

    这个问题在这里已经有答案了 我想将一个目录从 docker 容器挂载到本地文件系统 该目录是网站根目录 我需要能够使用任何编辑器在本地计算机上编辑它 我知道我可以跑docker run v local path container path
  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • 套接字:监听积压并接受

    listen sock backlog 在我看来 参数backlog限制连接数量 这是我的测试代码 server initialize the sockaddr of server server sin family AF INET ser
  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上

随机推荐

  • 测试开发——用例篇(如何设计一个测试用例,设计测试用例的一些具体方法)

    目录 一 测试用例的基本要素 二 设计测试用例的万能公式 在没有需求文档的情况下 1 水杯的测试用例 2 一个网站的登录测试用例 三 基于需求进行测试用例的设计 四 测试用例的具体设计方法 根据需求 1 等价类 2 边界问题 3 判定表 因
  • 阿里云云解析DNS各种概念深度剖析

    摘要 本文所设计概念有 主机记录 www 记录类型 A记录 CNAME记录 TXT记录 解析路线 isp 网络服务提供商 记录值 TTL time to live 缓存生存时间 地方DNS DNSPod 场景描述 域名解析有一个 记录数 和
  • KEIL5中点击build会全编译的解决方法

    今天在笔记本上调试STM32时 发现每次点击build 总是会对工程内所有文件进行编译 相当于是rebuild的功能 开始以为是keil5版本的问题 经过网上查找并亲自测试 现得出解决办法 在Option中C C 一栏内 添加路径包含工程内
  • 联想rd540服务器怎么装系统,联想RD540加显卡BIOS设置

    开机按F1进入BIOS设置界面 然后进入CONFIG子界面 找到Display这个子项 然后回车进入 这个是设置显示输入和显卡的地方 里面有三个项目 Boot Display Device 启动时使用的显示装置 1 保持默认Thinkpad
  • RabbitMQ修改数据目录MNESIA数据目录

    RabbitMQ修改数据目录MNESIA数据目录 一 什么情况要调整数据目录 1 1 磁盘空间不足 1 2 磁盘性能瓶颈 1 3 迁移集群的备份还原 1 4 数据分离 二 MNESIA简介 三 操作步骤 四 其他问题 4 1 重启失败 一
  • Python习题答案

    1 多选题 程序设计语言包括 和 执行两种方式 正确答案 AB A 编译 B 解释 C 脚本 D 编写 2 单选题 机器语言是一种 语言 正确答案 A A 二进制 B 八进制 C 十进制 D 十六进制 3 单选题 是将源代码转换成目标代码的
  • sqli靶场通关之less9

    sqli less9 时间盲注 结合burpsuite 1 不返回报错信息页面 无法进行基于报错信息的盲注 2 页面不存在true和false两种不同的页面 无法进行对比也就无法进行布尔盲注 一般来说 在页面没有任何回显和错误信息提示的时候
  • 【Python基础】面向对象基础和特性

    Python面向对象 面向对象基础 定义类 创建对象 添加和获取对象属性 魔法方法 对象的生命周期 私有属性和私有方法 面向对象特性 封装 封装案例演练 继承 继承的传递性 方法的重写 父类的私有属性和私有方法 多继承 新式类与经典类 多态
  • 平摊分析(Amortized analysis)

    今天我们主要讨论所谓的平摊分析 amortized analysis 它是用来分析一系列操作的平均所需要的代价 可能有人会问它利用概率论的知识 通过概率来求平均情况 答案是否定的 它并不涉及概率 在一些情况下平摊分析能够很好的帮助我们分析我
  • 三进制数位和

    1 问题描述 问题描述 给定L和R 你需要对于每一个6位三进制数 允许前导零 计算其每一个数位上的数字和 设其在十进制下为S 一个三进制数被判断为合法 当且仅当S为质数 或者S属于区间 L R 你的任务是给出合法三进制数的个数 输入格式 一
  • eclipse下创建webService服务

    本博客是记录在eclipse开发环境中将一个方法开放出去 提供一个webService接口 可以通过浏览器访问 开发环境 eclipse 下载地址 http www eclipse org downloads eclipse package
  • Linux高级专题篇详解--Mysql大全(数据库详细介绍,mysql类型,编译安装,yum安装,增删改查,权限管理,日志备份恢复,主从复制,mycat读写分离)

    Day01 一 数据库介绍 1 什么是数据库 数据库就是一个存放计算机数据的仓库 这个仓库是按照一定的数据结构 数据结构是指数据的组织形式或数据之间的联系 来对数据进行组织和存储的 可以通过数据库提供的多种方法来管理其中的数据 2 数据库的
  • android 编译时copy so文件

    因为项目只支持armeabi 而有些第三方库不支持armeabi 所以在编译时将v7 v8 so文件copy到armeabi 直接上代码build gradle中添加如下代码 afterEvaluate project gt android
  • 华为OD机试真题-数列描述-2023年OD统一考试(B卷)

    题目描述 有一个数列a N N 60 从a 0 开始 每一项都是一个数字 数列中a n 1 都是a n 的描述 其中a 0 1 规则如下 a 0 1 a 1 11 含义 其前一项a 0 1是1个1 即 11 表示a 0 从左到右 连续出现了
  • 【python简单介绍】

    1 Python起源与定义 Python 是由荷兰人吉多 罗萨姆于 1989 年发布的 Python 的第一个公开发行版发行于 1991 年 Python 的官方定义 Python 是一种解释型的 面向对象的 带有动态语义的高级程序设计语言
  • ORA-01799 列不能外部联接到子查询

    现有学生 考试 分数三张表 1 学生表 记录学生的学号 姓名 年龄 性别 2 考试表 记录考试及考试日期 3 学生分数表 记录学生考试分数 现在 想要查询最近一次考试每个学生的分数 查询sql如下 SELECT ST NAME SC SCO
  • 从头学Qt Quick(3)-- 用QML写一个简单的颜色选择器

    先看一下效果图 实现功能 点击不同的色块可以改变文字的颜色 实现步骤 一 创建一个默认的Qt Quick工程 二 添加文件Cell qml 这一步主要是为了实现一个自定义的组件 这个组件就是我们看到的那个色块 很明显定义成组件可以则兼UI的
  • STM32 USB DP/DM内置的上下拉电阻阻值

    根据USB协议 工作在主机模式 USB DP DM下拉到GND 工作在设备模式 上拉到VCC DP上拉表示高全速设备 DM上拉表示低速设备 STM32在Device模式只支持高速或全速 图片来源于 STM32F407数据手册 红色为示意 实
  • Ubuntu下搭建Android SDK开发环境(图文)

    1 安装JDK 点击打开链接参考这个就可以了 2 下载安装eclipse 这里的eclipse不能直接从ubuntu软件仓库中下载 那个软件仓库下载的eclipse在装ADT时会有问题 这里建议是从eclipse官网上下载 官网地址 htt
  • Linux的进程管理

    目录 1 概述 2 进程描述符 2 1 进程描述符的分配 2 2 进程描述符的存放 2 3 进程状态 2 4 进程上下文 2 5 进程家族树 3 进程的创建 4 进程的终结 5 线程的实现 1 概述 进程是执行期的代码 但是进程不止包括这样