进程概念
平常在任务管理器中我们会接触到进程
那么什么是进程?
进程=内核数据结构(PCB)+代码和数据
内核数据结构中存储着关于我们要执行的程序的详细信息,包括开始位置,结束位置,所指向的下一个进程等等
因此我们知道了进程的概念,同时计算机再启动时一定也会运行一个进程,操作系统。
你自己的所有操作可以说都是建立在操作系统上,
我们点击结束任务就是关闭了该程序的进程,所以说操作系统可以管理在其身上运行的各种程序。
类似父母与儿女之间的关系一样。
所以称呼类似这样的两个对应关系分别为父(操作系统)子(各种程序)进程。
PCB
进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
Linux操作系统下的PCB是: task_struct(PCB的一种,不同操作系统下名称不同,内容基本相同)
我们知道CPU只和内存(RAM)打交道,同时如果该程序好几百G,内存是无法存储的,所以人们用PCB去控制程序,用数据结构去操控不同的程序,不管程序大或小(不考虑内存能一次全加载完的),PCB都选择将程序代码切片加载,不仅不会浪费内存资源还能保证多个程序都能加载一些片段在内存中提高效率。
task_struct内容父类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
查看进程
1.ls /proc/
2.ls /proc/对应进程编号
3.使用ps工具获取进程信息
ps
是 “process status(进程状态)” 的缩写,是用于显示当前系统进程状态的工具。ps
命令的参数
a
代表 “all”,显示所有与终端相关的进程。u
代表 “user-oriented”,显示进程的用户和内存使用情况。x
代表 " processes without controlling ttys",显示所有进程,无论它们是否与终端关联。列出系统中所有进程及其详细信息,包括进程ID(PID)、用户、CPU使用率、内存使用情况等
grep管道--过滤内容(搜索文本中的字符串)
grep test_proc2--从 ps aux 的输出中筛选出包含 test_proc2 字符串的行。
grep -v(grep的一个选项) grep 排除那些包含 grep 字符串的行,即排除 grep 命令自身。
最终结果是,终端只显示与
test_proc2
相关的进程,而不显示grep
命令自身。
使用系统调用获取进程提示符
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("子进程pid :%d \n",getpid());
printf("父进程ppid :%d \n",getppid());
return 0;
}
getpid()->获取该程序的进程(子进程)
getppid()->获取该程序的父进程(都出来的p->parents父母)
进程id(PID)
父进程id(PPID)
创建进程fork
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret=fork();
if(ret<0)
{
perror("fork");
return 1;
}
else if(ret==0)
{
printf("child_id : %d! , ret %d\n " ,getpid(),ret);
}
else //father ret>0
printf("father_id : %d! , ret %d\n " ,getpid(),ret);
sleep(1);
return 0;
}
fork进程创建基本功能
fork()
调用在父进程中调用一次,但返回两次:一次在父进程中返回,一次在子进程中返回。- 在父进程中,
fork()
返回子进程的进程ID。一般都是>0- 在子进程中,
fork()
返回0。- 如果
fork()
调用失败,它返回一个负值。
进程状态
R 运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
S 睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
(interruptible sleep))。D 磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
T 停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
X 死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。当进程完成了它的执行并且已经退出时,它就会进入死亡状态。在这个状态下,进程实际上已经停止运行,但是它的进程表项(process table entry)仍然存在于系统中,以便父进程可以获取它的退出状态。(未获取退出状态但已经退出的进程)
进程状态查看
ps aux / ps axj 命令
a
:显示所有与终端有关的进程,包括其他用户的进程。x
:显示没有控制终端的进程。j
:以作业控制格式显示信息,这意味着输出将以作业为单元来组织。ps aux
命令通常用于查看所有进程的详细列表,而ps axj
命令则更侧重于进程之间的组织关系。
Z 僵尸进程
僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态危害
- 进程的退出状态必须被维持下去,他要告诉关心它的进程(父进程),父进程需要明确该子进程的具体运行结果,方便系统调用。若父进程一直不知道具体完成状态则会一直等待。
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护?是的!
- 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
孤儿进程
- 父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
- 父进程先退出,子进程就称之为“孤儿进程”
- 孤儿进程被1号init进程领养,当然要有init进程回收喽。
查看系统进程
ps –l命令查看
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍生而来的,即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行(优先级级数越小,越早运行)
- NI :代表这个进程的nice值
- 就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。
调整进程优先级,在Linux下,就是调整进程nice值(注意:nice值不是优先级,nice值是一个工具,通过它取调整优先级PRI的大小)
nice其取值范围是-20至19,一共40个级别。修改nice值
默认情况下NI值都为0
修改时:
通过ps axj | grep nice_fork查看某个进程的pid
进入top 在新窗口中输入top
按“r”–>输入进程PID,回车–>输入nice值,回车
注意nice值只能在-20至19之间40个级别
并发和并行区别
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行(银行内多个窗口能同时让多人取钱)
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发(银行内单个窗口只能排队取钱并有时间限制)
性质
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰