Linux学习之路(16)

进程管理:

一、基础概念

1、进程和程序的区别

       程序是放到磁盘的可执行文件
       进程是指程序执行的实例

2、进程的特点

      动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
      并发性:任何进程都可以同其他进程一起并发执行
      独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
      异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
      结构特征:进程由程序、数据和进程控制块三部分组成.

 

3、进程死锁

     多个进程因竞争资源而形成一种僵局,若无外力作用,这些进程都将永远不能再向前推进。

 

二、进程控制编程

1、获取ID

2、进程创建fork()

      当fork()顺利完成任务时,就会存在两个进程,每个进程都从fork()返回处开始继续执行。         
两个进程执行相同的代码(text)段,但是有各自的堆栈(stack)段、数据(data)段以及堆(heap)。
子进程的stack、data、heap segments是从父进程拷贝过来的。
fork()之后,哪一个进程先执行(scheduled to use the CPU)不确定。
 
 
     fork()之后,不能确定哪个进程先执行,会有什么隐患吗?   
     产生原因:
      fork()之后,不能确定是父进程还是子进程获得CPU。 
危害:
    这种bugs很难被发现。 
措施:
    如果需要确保特定的执行顺序,需要采用某种同步(synchronization)技术(semaphores,file locks...)。

 

3、exec函数族

execl:#include <unistd.h>
int execl(const char * path, const char* arg1,...)
参数:
path : 被执行程序名(含完整路径)。
arg1 - argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。

execlp:#include <unistd.h>
int execlp(const char * path, const char* arg1,...)
参数:
path : 被执行程序名(不含路径,将从path环境变量中查找该程序)。
arg1 - argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。

execv:#include <unistd.h>
int execv(const char * path, const char *argv[])
参数:
path : 被执行程序名(含完整路径)。
argv[]: 被执行程序所需的命令行参数数组。

system:#include <stdlib.h>
 int system(const char* string)
功能:
调用fork产生子进程,由子进程来调用 /bin/sh -c string来执行参数string所代表的命令

4、进程的终止

终止函数

exit():表头文件: #include<stdlib.h>
定义函数: void exit(int status);
函数说明:
exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。

_exit():表头文件: #include<unistd.h>
定义函数: void _exit(int status);
函数说明
      此函数调用后不会返回,并且会传递SIGCHLD信号给父进程,父进程可以由wait函数取得子进程结束状态。

僵尸进程:僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸。
如何产生?
如果一个进程在其终止的时候,自己就回收所有分配给它的资源,系统就不会产生所谓的僵尸进程了
 
僵尸进程产生的过程:
1. 父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。
 
2. 子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。

父进程比子进程先退出:

若父进程比子进程先终止,则该父进程的所有子进程的父进程都改变为init进程。我们称这些进程由init进程领养。其执行顺序大致如下:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止的进程的子进程,如果是,则该进程的父进程ID就更改为1(init进程的ID);
 
 有init领养的进程不会称为僵死进程,因为只要init的子进程终止,init就会调用一个wait函数取得其终止状态。这样也就防止了在系统中有很多僵死进程。

 

5、进程等待

wait和waitpid:#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options); 
返回值:若成功返回进程ID,若出错返回-1。
 
    调用wait或waitpid的进程可能发生的情况有:
 如果所有子进程都还在运行,则阻塞(Block)。
 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
 如果它没有任何子进程,则立即出错返回。
 
 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
 waitpid并不等待在其调用之后的第一个终止的子进程。它有若干个选项,可以控制它所等待的进程。
    如果一个子进程已经终止,并且是一个僵死进程,wait立即返回并取得该子进程的状态,否则wait使其调用者阻塞直到一个子进程终止。如果调用者阻塞并且它有多个子进程,则在其一个子进程终止时,wait就立即返回。因为wait返回终止子进程的ID,所以总能了解到是哪一个子进程终止了。
 
注:僵死进程(zombie),一个已经终止、但是其父进程尚未对其进行善后处理(获得终止子进程的有关信息,释放它仍占用的资)的进程被称为僵死进程。

waitpid:

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid (pid_t pid, int * status, int options)
功能:会暂时停止目前进程的执行,直到有信号来到或子进程结束
 
参数:如果不在意结束状态值,则参数status可以设成NULL。
参数pid为欲等待的子进程识别码:
pid<-1 等待进程组识别码为pid绝对值的任何子进程。
pid=-1 等待任何子进程,相当于wait()。
pid=0 等待进程组识别码与目前进程相同的任何子进程。
pid>0 等待任何子进程识别码为pid的子进程。
 
参数option可以为0 或下面的OR 组合
WNOHANG:  如果没有任何已经结束的子进程则马上返回,不予以等待。
WUNTRACED :如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。

返回值:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。

 

 

 

 

 


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值