【进程与线程】进程的基础
什么是进程?
进程是程序的一次执行过程,进程是一个独立的可调度的任务,进程是资源管理的最小单位,线程是CPU调度的最小单位。
进程和程序的区别?
- 程序是静态的,保存在磁盘上有序的指令集合,进程是动态的,表示程序的一次执行过程,包括创建,调度,和消亡。
- 程序包含代码块,部分用户数据,进程包含代码块,用户数据(运行时栈,运行时堆),系统数据。
- 一个程序对应多个进程,一个进程只能对应一个程序。
- 程序可以永久保存,进程是短暂的。
进程控制块PCB
参考文章:进程控制块(Process Control Block, PCB)
本质是一个超大的结构体 - struct task_struct
,每创建一个进程都会生成一个PCB对象来描述这个进程。
进程的分类
- 交互进程:该类进程由shell控制和运行,交互进程既可以在前台运行,也可在后台运行。
- 批处理进程:该类进程不属于某个终端,它被提交到一个队列中以便顺序执行(
gcc shell
脚本) - 守护进程(后台进程,精灵进程):该类进程在后台运行,一般在
Linux
启动时开始执行,系统关闭时才结束。
进程的特点
参考文章:进程管理
- 独立性:每个进程都有自己独立的4GB虚拟空间
- 并发性:多个进程可以同时进行(单核CPU采用的是伪并发)
- 异步性:进程间运行互不干扰
- 动态性: 进程的状态不固定,处于动态变化的过程
进程的相关查看指令
ps -aux //静态查看
top //动态查看,每隔5秒刷新一次
pstree -p //以树形的结构展示各进程之间的关系,-p展示进程的ID即PID号
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
USER: 进程的用户名
PID: 进程的ID --- 进程的身份证号
%CPU: CPU的占用率
%MEM: 内存占比
VSZ: 虚拟内存
RSS: 物理内存的使用量
TTY: 终端
STAT: 进程的状态
S:休眠 , 可中断
D:休眠 , 不可中断
I:空闲 , 可暂时不管
R:运行态
T:暂停态
Z:僵尸态
X:死亡态
s:进程领导者(多进程)
l:线程领导者(多线程)
<:高优先级
N:低优先级
+:在前台运行的进程
ps -elf查看优先级
优先级和谦让度
在操作系统中,进程的调度是根据一定的策略来决定哪个进程优先运行,其中 进程的优先级 和 谦让度(或叫静态优先级调整) 是两个重要的调度参数。
【ps -elf 查看优先级】
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
其中PRI(priority) 显示的优先级(LINUX进程的优先级 - 40,即显示的优先级范围为: -40 ~ 99)
NI(nice) 谦让度
1> LINUX进程的优先级:
定义:优先级 是操作系统为每个进程分配的一个数值,表示进程的重要性或需要被调度的优先程度。
优先级越高的进程通常会比优先级低的进程更早获得 CPU 时间。
优先级类型:
1.静态优先级:
- 在进程创建时由操作系统分配,通常不会改变。
- 用户也可以通过命令或系统调用手动设置进程的静态优先级。
- 适合实时系统(如硬件控制系统),需要严格保证某些任务的执行顺序。
2. 动态优先级:
- 操作系统在运行时根据进程的行为动态调整优先级。
- 例如:① 长时间未获得 CPU 的进程,其优先级可能会提高(防止饥饿)。② 占用 CPU 时间过多的进程,其优先级可能会降低(避免进程过于霸占资源)。
优先级范围:
(Linux系统):
静态优先级范围:0 ~ 139,140个优先级 --- 数字越小,优先级越高
实时优先级(实时进程):0 ~ 99 共100个(显示的优先级范围: -40 ~ 59)
非实时进程(普通进程): 100 ~ 139 共40个 (显示的优先级范围: 60 ~ 99)
(Windows 系统):
优先级分为 32 个级别(0 到 31)。
优先级 0:用于系统空闲进程。
优先级 1 到 15:普通进程。
优先级 16 到 31:实时进程。
影响调度的机制:1. 优先级调度算法通常会优先运行优先级较高的进程。2. 如果两个进程的优先级相同,则按照其他调度策略(如先来先服务)决定调度顺序。
2> LINUX进程的谦让度:
定义:谦让度 是一种静态优先级调整机制,用于改变普通进程的优先级,从而影响进程获得 CPU 时间的概率。
谦让度是一种用户可调参数,表示进程对 CPU 时间的“谦让程度”:
谦让度越高,进程优先级越低(更少使用 CPU)。
谦让度越低,进程优先级越高(更倾向获得 CPU)。
谦让度的范围
(Linux系统中):
-20 ~ 19,默认是0,数字越大,谦让度越高,越晚执行;数值越小,谦让度越低,越早执行。
当谦让度为 0 时,优先级为 80
谦让度会影响动态优先级的计算:
实际显示的优先级(由优先级和谦让度共同影响) = 优先级(NI为0的时候的优先级,即80) + NI
动态优先级 = 静态优先级 + 谦让度。(谦让度的值直接调整静态优先级,从而间接影响调度顺序)。
如何修改(调整谦让度):
1> 程序运行前:(使用 nice 命令启动进程,并指定谦让度):
nice -n 谦让度 进程的名称(./程序名)
2> 程序运行后:(使用 renice 命令调整已运行进程的谦让度:)
renice -n 谦让度 -p 进程的PID号
如果出现这个问题,说明权限不够,需要加上sudo
renice: failed to set priority for 50089 (process ID): Permission denied
使用代码的方式设置谦让度:(调用 nice()
函数设置谦让度:)
#include <unistd.h>
#include <stdio.h>
int main() {
int ret = nice(10); // 设置谦让度为 10
if (ret == -1) {
perror("Failed to set niceness");
}
printf("Current niceness: %d\n", ret);
return 0;
}
优先级和谦让度是相辅相成的,优先级 决定了进程在调度中的重要性。谦让度 是一种用户级别的优先级调整方式,可以改变普通进程的调度顺序。
动态优先级计算公式(Linux 中)的代码实现:
- 假设某进程的静态优先级为 120,谦让度为 10,则动态优先级为:
动态优先级 = 120 + 10 = 130
- 如果另一个进程的谦让度为 -5,则动态优先级为:
动态优先级 = 120 + (-5) = 115
# 在这种情况下,动态优先级较低的进程(115)会优先调度。
前端进程和后端进程
参考文章:【进程与线程】前端进程与后端进程
前端进程和后端进程经常需要通信以完成用户请求、数据处理等任务。通信方式因场景和系统架构而异:
如何切换:
./swtich 前端进程 //状态栏里有 + 号
./swtich & 后端进程 //状态栏里没有 + 号
后端进程->前端进程:
jobs //查看进程的标号
fg n //n为jobs查看到的标号
前端进程->后端进程
ctrl + z //暂停
jobs //查看标号
bg n //n为jobs查看到的标号
进程的操作指令
查看更多详情请参考:【Linux系统】进程管理
kill指令 :给进程发送相应的信号
kill -l
【信号的发送方法 : kill -信号的标号 进程的PID】
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
1) SIGHUP --->在终端结束时,会给该终端下所有的进程发送该信号以结束
*2) SIGINT --->结束进程 ctrl + c
3) SIGQUIT --->结束进程 ctrl + \
*9) SIGKILL --->强制结束进程 (不能被捕捉,不能被忽略,不能被阻塞 【天王老子来了都不好使,就是干】)
*10) SIGUSR1 --->用户自定义信号
*12) SIGUSR2 --->用户自定义信号
*14) SIGALRM --->闹钟信号,倒计时归零时,结束进程 alarm();
17) SIGCHLD --->子进程结束时,给父进程发送的信号
*18) SIGCONT --->继续进程
*19) SIGSTOP --->暂停进程 (不能被捕捉,不能被忽略,不能被阻塞 【天王老子来了都不好使,就是干】)
20) SIGTSTP --->暂停进程 ctrl + z
进程的状态
查看更多详情请参考:进程的状态
就绪态,运行态,阻塞态,暂停态,僵尸态,死亡态(具体切换请查看 进程的切换.png)
进程的PID获取:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); //获得自己的PID
pid_t getppid(void); //获得父进程的PID
进程的调度
查看更多详情请参考:进程的调度
遵循原则:
1> 先来先执行规则
2> 短进程先执行规则
3> 高优先级优先执行规则
4> 时间片轮转
进程常见的API函数
查看更多详情请参考:进程常见的API函数
生老病死 和 进程死亡的三种状况:老死、他杀(`kill -9 PID`)、自杀(`exit`)。
以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。
我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!