【Linux】进程概念——入门了解
·
文章目录
1.冯诺依曼操作系统

| 结构 | 常见实体(硬件) |
|---|---|
| 1. 输入设备 | 键盘、鼠标、麦克风、摄像头、扫描仪 |
| 2. 输出设备 | 显示器、音箱、打印机、投影仪 |
| 3. 存储器 | 内存条(RAM)、ROM、Cache(高速缓存) |
| 4. 运算器 | CPU 中的 ALU(算术逻辑单元) |
| 5. 控制器 | CPU 中的控制单元(CU) |
2.操作系统

操作系统包括:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell 程序等等)
作用
- **先描述:**把要管理的东西弄成一个可以描述、量化 的 某种数据结构,可能是结构体
- 例如:Linux 内核用
task_struct描述进程,记录 PID、进程状态、调度信息等。
- 例如:Linux 内核用
- **再组织:**用链表、队列、哈希表等结构,把上面的结构体串起来,
- **最后管理:**增删查改、调度。
描述是建立对象的信息模型,组织是建立对象之间的管理关系,管理则是对资源进行实际操作。
3.进程
进程 = 内核数据结构(task_struct) + 程序的代码和数据
描述
描述:把要管理的东西弄成一个可以描述、量化 的 某种数据结构,可能是结构体
- PCB(process control block):所有操作系统都会有的,一种用来控制进程的 数据结构 ,可以理解为进程属性的集合。
- task_ struct:Linux中的PCB。里面有各种各样的东西:pid:进程 ID;uid/gid:用户、组 ID等等
组织
多个task_struct连起来,形成一个双链表

获取PID
- pid:进程 ID
- ppid:父进程 ID
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
return 0;
}
僵尸进程
- 进程状态是Z状态
- 原因
- 子进程先退出,父进程还活着,但没调用 wait/waitpid 收它的退出信息。
- 子进程的 task_struct(PCB)不会被内核删掉,就变成僵尸进程。
- 它已经不跑代码、不占 CPU,只留一条进程记录放退出码,等父进程读取。
- 危害:
- 僵尸的 PCB 占内核进程表,大量僵尸会耗尽 pid 资源。
- 解决:
- 父进程 wait 回收;或者父进程先退出,子进程被 init 收养,init 会自动回收。
孤儿进程
- 父进程先退出了,子进程还在运行,这个子进程就是孤儿进程
- 孤儿进程会自动被 init 进程(pid=1) 收养,init 变成它的新父进程
- 等孤儿进程结束的时候,init 会自动调用 wait 帮它回收,不会变成僵尸进程
4.进程调度
进程优先级
在linux或者unix系统中,用ps -l命令则会类似输出以下⼏个内容:
- UID:代表执行者的身份
- PID:代表这个进程的代号
- PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI:代表这个进程可被执行的优先级,其值越小越早被执行
- NI:代表这个进程的nice值,
PRI(new)=PRI(old)+nice- 当nice值为负值的时候,PRI将变小,即 优先级会变高,则其越快被执行
- 调整进程优先级,在Linux下,就是调整进程nice值
- nice其取值范围是-20⾄19,⼀共40个级别。
- ⽤top命令可以更改已存在进程的nice
竞争、独立、并行、并发
- 进程有优先级,因为CPU资源少,为了高效完成任务,更合理竞争相关资源,便具有了优先级
- 独立性:多进程运行, 运行期间互不干扰
- 并行:多个进程在多个 CPU 下分别,同时进行运行,这称之为并行
- 并发:多个进程在一个 CPU 下采用进程切换的方式,CPU来回切换进程,让多个进程都得以推进,称之为并发
进程切换
进程切换,就是CPU换一个进程来运行。
比如从A切到B:
- 保存A“执行到哪了、正在用哪些数据”。
- 恢复B上次保存的状态。
- B接着上次停下的地方继续运行。
这些需要保存的状态,就叫上下文,主要放在CPU寄存器里。
像做题做到一半,夹好书签,再换另一本书;回来时按书签继续。
5.环境变量
是什么
- 一些参数,程序跑的时候能拿来参考
常见环境变量
- PATH:指定命令的搜索路径
- HOME:指定用户的主工作目录 (即用户登陆到 Linux 系统中时,默认的目录)
- SHELL:当前 Shell, 它的值通常是 /bin/bash。
查看环境变量
echo $NAME //NAME:你的环境变量名称
getenv
- 头文件:
#include <stdlib.h> - 原型:
char *getenv(const char *name); - 作用:C 程序里读取环境变量,相当于代码版
echo $xxx - 返回:找到 → 返回值字符串指针;找不到 → 返回
NULL
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *path = getenv("PATH");
if(path) printf("%s\n", path);
return 0;
}
6.程序地址空间
之前学的
- 之前学的:(如图,实际上并不是这样,这是)

为什么是虚拟地址空间
地址一样
- 运行如下代码,输出出来的变量值和地址是⼀模⼀样的
- 因为子进程按照父进程为模版,子并没有对变量进行进行任何修改。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if(id < 0){
perror("fork");
return 0;
}
else if(id == 0){ //child
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}else{ //parent
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
内容不一样
稍微改一下代码,变成下面这样,运行后就会发现我们发现:父子进程,输出地址是⼀致的,但是变量内容不⼀样!
说明,是虚拟地址!
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if(id < 0){
perror("fork");
return 0;
}
else if(id == 0){ //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
g_val=100;
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}else{ //parent
sleep(3);
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
进程地址空间
- 实际上的地址空间是这样的:如图
- 地址相同,其实是虚拟地址相同,内容不同其实是:被映射到了不同的物理地址!

虚拟内存管理
- 进程的
task_struct结构中,有一个指针,指向一个特殊的结构体,结构体是mm_struct(内存描述符)。 mm_struct用来描述用户空间- 那么每⼀个进程都会有自己独立的 mm_struct(先描述),操作系统肯定是要将这么多进程的 mm_struct组织起来的!(再组织)
- 具体怎么组织,可能用单链表,可能用红黑树

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)