进程的概念:
操作系统:
一款搞管理的软件
什么是进程:
进程:运行起来的程序
操作系统对进程做了哪些描述:
-
标识符(pid) 操作系统给进程的ID
-
状态 表示进程现在的状态
-
内存指针
-
I/O状态信息
-
记账信息 一个进程在CPU上运行的时间等信息
-
优先级
-
程序计数器——用于保存程序运行的下一条指令
-
上下文数据——用于保存进程切换时寄存器上的数据
-
我们现在操作系统都是多任务多用户操作系统
-
分时机制(其实同一时间只有一个进程在运行,但是CPU一直在不停的切换,给我们的假象就是他们同时在运行)————时间片
-
多个进程在CPU上进行切换运行:(我们正在写vs上的++操作,但是时间片到了,切换到别的进程中,当下一次再切换回来时,++操作命令丢失,因为只有一个缓存区,为了解决这个问题,就引入了程序计数器,和上下文数据)
-
交互式进程——和我们用户正在交互的进程
-
批处理进程——在后台默默的进程(假设交互只有一个,批处理有一堆。导致交互了一下,然后卡好久处理批处理,所以引进优先级)
查看进程信息:
进程的创建:
pcb里内存指针指向内存的一块空间(程序数据,create程序),当需要一个新的进程时通过fork()函数创建一个子进程,他完全复制了父进程的所有信息。和父进程的程序计数器相同,下一步他们将运行相同的指令。那么如何区分父子进程?
进程的状态:
-
运行状态(running):意味着程序进程要么正在运行中,要么就在运行队列了。
-
睡眠状态(sleeping):意味着可中断睡眠状态,等待事件完成
-
磁盘睡眠状态(disk sleeping):不可中断睡眠(植物人)主要磁盘,是不可被中断的。
-
停止状态(stopped):对比睡眠状态,睡眠状态只是正在睡眠,而停止状态是什么都不干
-
追踪状态(tracing stop)
-
死亡状态(dead):出现非常快
-
僵尸状态(zombie)
僵尸进程:
-
产生原因:子进程先于父进程退出,他要保留退出原因,在PCB中,因此退出后,不会释放所有资源,子进程退出后操作系统会通知父进程这个家属说子进程退出了,你去获取一下原因,然后完全释放资源。假如父进程不管子进程的退出状态,那么这个子进程将进入僵死状态,成为僵尸进程。
-
危害:资源泄露
孤儿进程:
-
产生原因:父进程先于子进程退出,那么这个子进程将会被成为孤儿进程,并进入后台运行
-
解决方法:系统init进程变为父进程,也就是说子进程如果后来退出了,init进程将负责释放资源。init进程非常负责任,因此子进程不会成为僵尸进程。
优先级:
-
为什么要有进程的优先级?
多个进程同时进行中的进行,因为进程的功能各有不同,因此对CPU资源的要求也各有不同。因此对进程的调度,就有了优先级。优先级决定了CPU资源的优先分配权限。
-
PRI 优先级 默认80, 值越低,越优先。
-
NI nice值 设置进程优先级的参数
-
进程的优先级:PRI+NI的值为优先级。
-
renice [-n] priority [[-p] pid …] [[-g] pgrp …] [[-u] user …]
-
进程具有:竞争性、独立性、并行、并发
环境变量:
windows下面也有环境变量,点击我的电脑,管理,高级系统设置,环境变量。ls执行时,不需要添加路径,而执行某个文件前例如.c文件生成的test在执行前需要加./来告诉操作系统,而ls不需要添加的原因就是,linux操作系统的环境变量给ls路径。
-
查看环境变量env
-
echo除了打印内容到屏幕上以外,还可以打印变量,前面加一个$来表明不是字符串
-
main函数第三个参数env
-
extern char ** environ
-
.c文件中可以用getenv获取环境变量的值。还有一个putenv
-
set也可以查看环境变量,unset,取消一个环境变量
cpu如何对进程进行调度切换
-
进程就是pcb(task_struck)
-
task_struck中内存指针,程序计数器,上下文数据
-
pid_t vfork(void);
-
区别:
进程终止:
-
终止方式:
进程的等待:
我们的进程退出之后,资源并非全部释放,我们有一个错误原因。保存在pcb中。所以为了保存错误原因,进程并不会完全退出,而是等待他的父进程来获取原因。假如父进程根本就没管,那么这个子进程就成了僵尸进程。危害就是资源泄露。因此为了防止出现僵尸进程,父进程就应该管一下子进程的退出。
父进程会专门关注(等待)子进程的状态。如果子进程退出,父进程会立马释放子进程资源。进程等待是避免为了产生僵尸进程的主要方式。
-
这里的pid_t,就是说,一个父进程会有无数个子进程,他得知道是哪一个。pid_t就说获取退出的子进程的pid。status用于获取子进程 退出代码。返回值是返回退出的子进程pid。如果没有子进程,他会返回一个-1。显示的是报错。错误原因是调用进程根本没有子进程。他是一个阻塞性函数,就是说如果没有等到进程退出,他就挂起一直等待,直到等待到有子进程退出。
-
pid_t waitpid(pid_t pid, int *status, int options);
进程的替换:
程序替换相当于让我们的虚拟地址空间中的代码段的地址指向了物理内存的另一端代码位置。这样的话,虚拟地址空间中,原先的数据区域以及堆栈都会重新初始化,因为现在的代码运行的根本不是复制的那些数据。
-
但这个进程的PCB还是原来的PCB。
-
一个程序main有三个参数,参数个数,参数的字符串指针,环境变量
-
exec函数族:exec并非函数,而是一个函数家族的名称
-
int execl(const char *path, const char *arg, …);
-
int execlp(const char *file, const char *arg, …);
-
int execle(const char *path, const char *arg, …, char * const envp[]);
-
int execv(const char *path, char *const argv[]);
-
int execvp(const char *file, char *const argv[]);
-
int execve(const char *filename, char *const argv[],char *const envp[]);
-
execl和execv的区别:l是参数平铺一个一个通过exec函数参数赋予,v参数直接使用字符串指针数组。
-
-
execl和execv 需要我们给出要替换程序的全路径名
-
execlp/execvp 只需要给出要替换的程序的名称就
-
execle 重新自己组织环境变量,不使用现有的。(就想说,父进程拥有自己的环境变量,创建出的子进程和父进程,本来一样,但是execle函数,就是说,他清空原有的环境变量。)