fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数执行另一个程序。当进程调用一个exec函数时,该进程的用户空间和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程ID不变.
将当前进程的.text .data替换为所要加载程序的.text .data,然后让进程从新的.text第一条指令开始执行,但进程ID不变,换核不换壳.
int execl();
int execlp();
int execle();
int execv();
int execvp();
int execve();
孤儿进程
父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程。
僵尸进程
进程终止,父进程尚未回收,子进程残留资源存放于内核中,变成僵尸进程.
特别注意,,僵尸进程是不能用kill命令清除掉的。因为kill命令只是用来终止进程的,而僵尸进程已经终止。那用什么方法可清除掉僵尸进程?
wait函数
一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但他的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存退出状态,如果是异常终止则保留着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在shell中用特殊保留$?查看,因为shell是它的父进程,当它终止时shell调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。
父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:
1.阻塞等待子进程退出
2,。回收子进程残留资源
3.获取子进程结束状态。
pid_t wait(int * status)成功:清理掉的子进程ID:失败-1
当进程终止时,操作系统的隐式回收机制会:
1.关闭所有文件描述符
2.释放用户空间分配的内存。内核的PCB仍在。其中保存该进程的退出状态
waitpid函数
作用和wait相同,但可以指定pid进行清理,可以不阻塞
一次wait或waitpid函数调用只能回收一个子进程,清理多个子进程应使用循环
exec函数族
execlp --p =path 系统可执行程序
execl --list 用户自定义可执行程序
execv v 命令行参数
execvp
execve 环境变量
只有失败返回值,-1
IPC 进程间通信
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷贝到内核缓冲区,进程2在从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信IPC.
在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件,管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的发展,一些方法由于自身设计缺陷被淘汰或弃用。现今常用的进程间通信方式有
1.管道(使用最简单)
2.信号(开心最小)
3.共享映射区(无血缘关系)
4.本地套接字(最稳定)
管道
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统还是即可创建一个管道。有如下特质:
1.其本质是一个伪文件(实为内核缓冲区)
2.有两个文件描述符引用,一个表示读端,一个表示写端。
3.规定数据从管道的写端流入,从读端流出。
管道的原理:管道实为内核使用环形队列机制,借助内核缓冲区实现(4k);
管道的局限性:
1.数据自己读不能自己写。
2.数据一旦被读走,便不在管道中存在,不可反复读取。
3.由于管道采用半双工通信方式,因此,数据只能在一个方向上流动
4.只能在有公共祖先的进程间使用管道。
常见的方式有:单工通信 半双工通信 全双工通信
伪文件
共享存储映射
使用文件也可以晚上IPC,理论依据是,fork后,父子进程共享文件描述符。也就共享打开的文件。
存储映射IO
存储映射(memory-mapped IO) 使一个磁盘文件与存储空间的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可以在不使用read和write函数的情况下,使用地址(指针)完成IO操作。
使用这种方法,首先应通知内核,将一个指定文件映射的储存区域中。这个映射工作可以通过mmap函数来实现
malloc大小可以为0
mmap 大小不可以为0
目录项
匿名映射
通过使用我们发现,使用映射区来完成文件读写操作十分方便,父子间通信也容易。
缺陷是每次创建映射区一定要依赖一个文件才能实现。通常为了建立映射区要open一个temp文件,创建好了再unlink,close 比较麻烦。可以直接使用匿名映射来代替。其实Linux系统给我们提供了创建匿名映射区的方法,无需依赖一个文件即可创建映射区。同样需要借助标志位参赛flags来指定