进程概述(进程一)

进程:计算机中资源分配的最小单元。
进程可以是从命令行执行的一个命令(短期),也可以是一种网络服务(长期)。
对进程及其调度进行管理显得十分重要。
单CPU的计算机在一个时间片内只能执行一条指令。
进程调度(Process Scheduling):
首先为每一个进程指派一定的运行时间,这个时间通常非常短,短到以毫秒为单位,然后依照某种规则,从众多进程中挑选一个投入运行,其他进程暂时等待,当正在运行的那个进程时间耗尽,或执行完毕退出,或因某种原因暂停,Linux就会重新进行调度,挑选下一个进程投入运行。因为每个进程占用的时间片都很短,从使用者角度来看,就好像多个进程同时运行一样。
在Linux中,每个进程在创建时都会被分配一个数据结构,称为程序控制块(PCB)。
PCB中最重要的是进程ID(PID),PID也被称为进程标识符,是一个自然数,在Linux操作系统中唯一地标志一个进程。

进程分类:
1、 交互进程;
2、 批处理进程;
3、 守护进程;
守护进程总是活跃的,一般在后台运行,守护进程有系统在开机时通过脚本自动激活启动或超级用户root来启动。
由于守护进程是一直运行着的,所以它所处的状态是等待请求处理任务。

进程的属性:
1、 进程ID(PID):是唯一的数值,来区分进程;
2、 父进程和父进程的ID(PPID);
3、 启动进程的用户ID(UID)和所归属的组(GID);
4、 进程状态:运行R、休眠S、僵尸Z;
5、 进程执行的优先级;
6、 进程所连接的终端名;
7、 进程资源占用,如占用资源大小(内存、CPU占用量)。

父进程和子进程:
父进程和子进程的关系是管理和被管理的关系,当父进程终止时,子进程也随之终止;但子进程终止,父进程并不一定终止。
在进程管理中,当我们发现占用资源过多,或无法控制进程时,应该杀死它,以保证系统的稳定安全运行。

Linux进程的三态
一般情况下,一个运行进程必须具有以下三种状态:
1、 就绪状态:当进程已分配到除了CPU以外所有必要的资源,只要获得处理器便可立即执行,这时的进程状态称为就绪状态;
2、 执行状态:当进程已获得处理器,其程序正在处理器上执行,此时的进程状态成为执行状态;
3、 等待状态(阻塞):正在执行的进程,由于等待某个事件
三种状态之间的转换:
一个进程在运行期间,会不断地从一种状态转换到另一种状态,它可以多次处于就绪状态和执行状态,也可以多次处于阻塞状态。
1、 就绪  执行 :处于就绪状态的进程,当进程调度程序为之分配了处理器之后,该进程便由就绪状态转变为执行状态;
2、 执行  就绪 :处于执行状态的进程在其执行过程中,因分配给它的一个时间已用完而不得不让出处理器,于是进程从执行状态转变成就绪状态;
3、 执行  阻塞 :正在执行的进程因等待某种事件发生而无法继续执行,便从执行状态变成阻塞状态;
4、 阻塞  就绪 :处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。

Linux进程调度
任何时刻只能有一个进程或者线程处于执行状态,因此OS需要决定哪个进程执行,哪些进程等待,这就是进程的调度。
程序使用CPU的三种模式:
IO密集型、计算密集型、平衡型
IO密集型:响应时间非常重要;
计算密集型:CPU周转时间比较重要;
平衡型:响应和周转时间的平衡是最重要的。

调度算法:

在使用fork()创建一个进程时,子进程只是完全复制父进程的资源,复制出来的子进程有自己的task_struct结构和PID,但却复制了父进程其他所有的资源。这样得到的子进程独立于父进程,具有良好的并发性,但是两者之间的通信需要专门的通信机制。
通过fork()创建的子进程,需要将上面描述的每一种资源都复制一个副本。这样看来,fork是一个开销非常大的系统调用,然而这些开销并不是在所有情况下都是必须的。
fork()调用执行一次返回两个值,对于父进程,fork()返回子进程的进程号,而对于子进程fork()返回0,这就是一个函数返回两次的本质。
在fork()之后,子进程和父进程都会继续执行fork()调用之后的命令。子进程是父进程的副本,它将获得父进程的数据空间、堆和栈的副本,这些都是副本,父进程和子进程不共享这部分内存。也就是说,子进程对父进程中的同名变量修改不会影响它在父进程中的值。但是子进程和父进程又共享一些东西,简单地说就是程序的正文段。正文段存放着由CPU执行的机器指令,通常是read-only类型的。

vfork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码、组代码、环境变量、已打开的文件代码、工作目录和资源限制等。

注意:vfork()创建的子进程必须调用exit()来结束,否则子进程将不可能结束。

启动进程: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 *path , char *const argv[] , char *const envp[]);
以上函数只有execve是真正的系统调用,其他都是在此基础上经过包装的库函数。

exec函数族的作用是根据指定的文件名找到可执行的文件,并用它来取代调用进程的内容。换句话说,也就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
与一般情况不同,exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段、数据段和堆栈等都已经被新的内容所取代,只有进程ID等一些表面的信息任然保持原样。只有调用失败了,它们才会返回-1,从源程序的调用点接着往下执行。

system用于执行shell命令。
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD信号会被暂时搁置,SIGINT和SIGQUIT信号则会被忽略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值