进程管理
本文最后更新于:2024年11月4日 晚上
进程管理
ELF
- linux下的ELF格式分析
- 程序运行环境
- 认识目标文件结构 - 云+社区 - 腾讯云 (tencent.com)
- 扒一扒ELF文件
- Linux ELF文件格式分析
- Linux系统中编译、链接的基石-ELF文件:扒开它的层层外衣,从字节码的粒度来探索
ELF加载
重定位
上下文切换
进程与线程
- 为什么进程地址空间中包括操作系统?
- 聊聊Linux中线程和进程的联系与区别!
- 浅析Linux下的task_struct结构体
- linux内核task_struct源码分析与解析(整合配图)
- Linux进程描述符task_struct结构体详解
- 从进程和线程的创建过程来看进程和线程的区别
- 一个进程最多可以创建多少个线程?
- Linux进程管理:深入task_ struct字段
- 【Linux】进程详解一:进程概念
fork
- 一个新进程的诞生 完结撒花!!!
- 【进程管理】fork之后子进程到底复制了父进程什么?
- 深入理解Linux中进程控制
- linux中fork()函数详解(原创!!实例讲解)
- 超详细的Linux进程控制精讲
- Linux 进程编程入门 fork vfork
内核线程
kernel_thread
session和进程组
在 Unix 操作系统中,进程组标识符(PGID,Process Group Identifier)和会话标识符(SID,Session Identifier)是用于组织和管理进程的两个不同的标识符。它们的主要区别在于它们所关联的层次结构和范围。
进程组标识符(PGID):
- 定义: 进程组是一个或多个进程的集合,每个进程组都有一个唯一的进程组标识符(PGID)。
- 关系: 进程组用于将一组相关的进程组织在一起。这些进程可以共享一些控制终端,以便它们可以在终端上进行协同工作。
- 创建: 使用系统调用 setpgid 可以创建新的进程组。
会话标识符(SID):
- 定义: 一个会话是一个或多个进程组的集合,每个会话都有一个唯一的会话标识符(SID)。
- 关系: 会话是更高层次的组织单位,它包含一个或多个进程组。一个会话通常对应于一个用户登录到系统的会话,但也可以通过 setsid 系统调用创建一个新的会话。
- 创建: 使用系统调用 setsid 可以创建新的会话。
总结来说,PGID 主要用于将进程组内的进程进行组织,使它们可以在同一终端上进行协同工作。而 SID 更高层次,它是一个会话的标识符,一个会话可以包含多个进程组,通常对应于用户登录会话。在创建新会话时,一个进程会成为新会话的首进程,并且新的会话会包含一个新的进程组。
内核栈
进程调度
- 你不得不知的linux内核进程调度策略
- 一文读懂进程调度算法
- 图解|Linux 组调度
- 图解Linux内核调度系统
- Linux进程调度:进程调度类与调度策略
- 玩转Linux内核进程调度,这一篇就够(所有的知识点)
- Linux进程调度
- CPU 空闲时在干嘛?
CFS调度器时间片
1 |
|
kernel/sched/core.c
文件中的 sched_prio_to_weight
数组定义了不同优先级(nice 值)对应的权重。权重决定了进程在调度中的相对重要性。nice 值越低,进程的优先级越高,对应的权重越大;nice 值越高,优先级越低,对应的权重越小。
数组中包含 40 个元素,分别对应 nice 值从 -20 到 19。数组中的值是这些优先级对应的权重,权重值越大,表示进程在调度中获得的 CPU 时间越多。
例如,sched_prio_to_weight[0]
对应 nice 值 -20,权重为 88761;sched_prio_to_weight[20]
对应 nice 值 0,权重为 1024;sched_prio_to_weight[39]
对应 nice 值 19,权重为 15。
这是一个常用的 CFS 调度权重表,用来计算进程的虚拟运行时间(vruntime)。具体来说,虚拟运行时间的计算公式是:
\[ \text{虚拟运行时间} = \text{实际运行时间} \times \frac{\text{基准权重}}{\text{当前进程的权重}} \]
其中基准权重一般取 sched_prio_to_weight[20]
(即 nice 值为 0 的权重 1024)。通过这种方式,不同优先级的进程会按照权重比例公平地分配 CPU 时间。
举例说明
假设有两个进程 A 和 B,分别具有以下 nice 值和权重:
- 进程 A:nice 值为 -10,对应的权重为 9548
- 进程 B:nice 值为 10,对应的权重为 110
假设这两个进程分别运行了 10 毫秒,虚拟运行时间的计算如下:
进程 A 的虚拟运行时间: \[\text{vruntime}_A = 10 \text{ms} \times \frac{1024}{9548} \approx 1.07 \text{ms}\]
进程 B 的虚拟运行时间: \[\text{vruntime}_B = 10 \text{ms} \times \frac{1024}{110} \approx 93.09 \text{ms}\]
可以看到,虽然进程 A 和 B 实际运行时间相同,但由于进程 B 的权重较小,它的虚拟运行时间增加得更快。因此,在 CFS 的调度策略下,进程 B 在下次调度时将被认为已经消耗了更多的 CPU 时间,从而更倾向于调度进程 A 以确保整体的公平性。
进程优先级
什么是进程优先级?
Linux进程的优先级是用来确定在多个进程同时运行时,哪个进程会获得更多的CPU时间片。
Linux进程的优先级分为实时优先级和普通优先级。
实时优先级用于实时应用程序,如硬实时任务和实时控制系统,而普通优先级用于非实时应用程序。
进程优先级原理
实时进程:动态优先级为0-99的进程,采用实时调度算法调度。
普通进程:动态优先级为100-139的进程,采用完全公平调度算法调度。
nice值:是用于调整普通进程优先级的参数。范围:-20-19。
prio(动态优先级)
- 动态优先级,有效优先级,调度器最终使用的优先级数值,范围0-139,值越小,优先级越高。
static_prio(静态优先级)
静态优先级,采用SCHED_NORMAL和SCHED_BATCH调度策略的进程(即普通进程)用于计算动态优先级的,范围100-139。
prio = static_prio = nice + DEFAULT_PRIO = nice + 120。
normal_prio(归一化优先级)
- 用于计算prio的中间变量,不需要太关心。
rt_priority(实时优先级)
实时优先级,采用SCHED_FIFO和SCHED_RR调度策略进程(即实时进程)用于计算动态优先级,范围0-99。
prio = MAX_RT_PRIO - 1 - rt_prio = 100 - 1 - rt_priority;
实时优先级数值越大,得到的动态优先级数值越小,优先级越高。
查看进程优先级
top中的PR和NI
top中的PR表示优先级,但是跟上述的值不是直接对等的。在top中,实时优先级的[0,99]没有具体的表示,统一用RT来表示。
而静态优先级和top中的优先级关系为:
- top_PR = static_prio - 100
也就是说,top中的PR取值为[0,39],对应图1的优先级[100,139]
top中的NI表示nice等级,nice的取值为[-20,19],对应图1中的优先级为[100,139],也就是说nice等级可以改变用户进程(非实时进程的优先级)。
在top界面中,输入r即可启动nice系统,先输入进程id,回车后再输入nice等级即可修改。
ps -elf 命令
执行ps -elf 命令查看进程优先级
PRI:进程优先级,数值越小,优先级越高。(并非动态优先级)
NI:nice值。
这里的PRI与图1 中的优先级关系为:
- ps_PRI = static_prio - 40
这边PRI的取值范围为[-40,99],也就是说,ps中PRI值为80等价于nice值为0,等价于静态优先级的120。
进程状态
僵尸进程
孤儿进程
文件描述符
信号
进程间通信
- 多进程编程知识汇总,附代码例子!
- 原来\进程间通信/是这么回事......
- Linux进程通信 - 无名管道与有名管道
- 用 abstract unix socket 实现进程单实例运行
- 进程间通信——重定向、描述符表
- Linux管道到底能有多快?
- 信号量函数(semget、semop、semctl)及其范例
- 全网最全、最详细的 Linux 进程间通信方式讲解来了,你不容错过!
System V IPC与POSIX IPC的区别
System V IPC(Inter-Process Communication)和 POSIX IPC 都是用于进程间通信的机制,但它们在实现方式和接口上有一些区别。
实现方式:
System V IPC 是早期 UNIX 系统引入的进程间通信机制,包括共享内存(Shared Memory)、消息队列(Message Queues)和信号量(Semaphores)。它们是通过系统调用(如 shmget、msgget、semget 等)来实现的。
POSIX IPC 是在 IEEE POSIX 标准中定义的进程间通信机制,包括命名管道(Named Pipes)、消息队列(Message Queues)、信号量(Semaphores)和共享内存(Shared Memory)。它们是通过标准的 POSIX 函数(如 mq_open、sem_open、shm_open 等)来实现的。
接口和使用:
System V IPC 的接口更底层,使用起来相对复杂,需要使用一系列的系统调用来创建和操作 IPC 对象。
POSIX IPC 提供了更高级的接口,使用起来更加简单和直观,通过标准的函数调用就可以完成大部分的操作。
跨平台性:
POSIX IPC 在设计上更加面向跨平台,因此具有更好的可移植性,在不同的 UNIX 系统上都有一致的接口和行为。
System V IPC 的接口和行为在不同的 UNIX 系统上可能会有一些差异,因此可移植性相对较差。
特性支持:
- System V IPC 提供了一些额外的特性,如消息队列中可以指定消息的优先级,而 POSIX IPC 则没有这个特性。
- POSIX IPC 提供了一些额外的安全特性,如命名对象的权限控制和更加严格的同步机制。
综上所述,System V IPC 和 POSIX IPC 在实现方式、接口和使用、跨平台性和特性支持等方面有一些区别,开发者可以根据具体需求和平台选择合适的 IPC 机制。
内核消息队列的实现
在内核中,消息队列是通过数据结构来实现的。一般情况下,消息队列的实现涉及到以下几个关键组件:
消息队列结构(Message Queue Structure):
- 内核中会维护一个或多个消息队列的结构,用于存储消息和管理消息队列的状态。这个结构通常包含队列的头指针、尾指针、消息数量、消息大小限制等信息。
消息结构(Message Structure):
- 每个消息都有自己的结构,在内核中会定义一个用于表示消息的结构体。这个结构体通常包含消息的内容、大小、发送者标识、接收者标识等信息。
内核函数(Kernel Functions):
- 内核会提供一系列函数,用于对消息队列进行操作,例如创建消息队列、删除消息队列、发送消息、接收消息等。这些函数会在用户态程序调用相应的系统调用时被调用,从而实现对消息队列的操作。
同步机制(Synchronization Mechanism):
- 为了保证多个进程对消息队列的并发访问不会出现冲突,内核中通常会使用一些同步机制来实现消息队列的互斥访问。例如,使用互斥锁、信号量或者其他的同步原语来保护对消息队列的操作,避免出现竞争条件。
系统调用接口(System Call Interface):
- 用户空间程序通过调用系统调用接口来访问内核提供的消息队列功能。例如,在 Linux 中,用户程序可以通过 msgget、msgsnd、msgrcv 等系统调用来创建、发送和接收消息。
综上所述,消息队列在内核底层是通过数据结构、内核函数、同步机制和系统调用接口等组件来实现的。内核会维护消息队列的状态并提供相应的接口供用户空间程序使用,从而实现进程间的通信。
互斥技术
percpu变量
amd64下基于per_cpu变量current_task获取task_struct
1
p ((struct task_struct*)(*(unsigned long*)((char*)__per_cpu_offset[0] + 0x15d00)))->comm