Linux——进程创建、进程终止、进程等待、进程程序替换

目录

一、进程创建

1.pid_t  fork(void);

2.pid_t  vfork(void);

 3.写时拷贝技术

4.进程拥有独立性——各有各的虚拟地址空间,映射各自数据存储

5.返回值

二、进程终止

1.进程常见退出方法

2.进程退出场景 

三、进程等待

进程等待的方法 

1.int  wait (int* status);    [status:输出型参数——用于获取退出子进程的返回值]

2.int  waitpid (int pid, int *status, int options);

3.获取子进程status (一个进程退出返回值只用了一个字节来保存)

四、进程程序替换


一、进程创建

创建一个进程就是创建一个pcb,pcb在Linux下是一个task_struct结构体,放在内核中,只能通过调用接口实现创建

1.pid_t  fork(void);

通过复制父进程创建一个子进程(复制了父进程pcb中的数据)

代码共享,数据独有

2.pid_t  vfork(void);

也是创建一个子进程,但是父进程使用vfork创建后,vfork的调用并不会立即返回(通常说会阻塞父进程),而是让子进程先运行,直到子进程退出或运行程序替换之后父进程才能运行(vfork创建的子进程若程序替换,调度运行新的程序,就会给自己开辟新的空间,与新的程序建立映射关系)

数据共用

vfork创建的子进程特殊的地方:父子进程共用一个虚拟地址空间(父进程的虚拟地址空间)

在程序运行中每调用一个函数就会有一次函数压栈——函数调用栈

父子进程使用了同一个栈,若父子进程同时运行会造成调用栈混乱,因此让子进程先运行,直到子进程退出或程序替换后有了自己的地址空间

注意:vfork创建的子进程不能在main函数中使用return退出,因为子进程使用return退出释放了所有资源,父进程运行的时候资源是错误的

 3.写时拷贝技术

子进程创建出来后,与父进程映射关系访问同一块物里内存(但虚拟地址空间及页表这些信息都是进程独有),当物里内存中数据即将发生改变时,重新为子进程开辟物理内存,拷贝数据过去

4.进程拥有独立性——各有各的虚拟地址空间,映射各自数据存储

进程之间没有交叉关系,不会受到其他进程运行影响,就是为了保证进程的稳定运行

5.返回值

子进程中返回0;父进程中返回子进程的pid;出错返回-1

二、进程终止

1.进程常见退出方法

(1)main函数中的return

普通函数中的return只能退出函数,不能退出进程

(2)void  exit (int status);

在任意位置调用程序的任意位置退出一个进程

(3)void  _exit (int status);

在任意位置调用程序的任意位置退出一个进程

问:exit和_exit的区别是什么?

答:exit是库函数,退出时会刷新缓冲区,将缓冲区的数据写入文件;

      _exit是系统调用接口,退出进程时直接释放资源,不会刷新缓冲区

2.进程退出场景 

正常退出:进程运行到return或exit的地方退出

异常退出:程序运行到中途崩溃了

不管子进程正常退出或者异常退出,只要是退出了,没有被父进程等待处理,就都会成为僵尸进程

三、进程等待

父进程等待子进程退出,为了获取退出子进程的返回值,释放退出子进程的所有资源,避免产生僵尸进程

僵尸进程产生的原因:子进程先于父进程退出,为了保存退出返回值而无法完全释放资源产生的

进程等待的方法 

1.int  wait (int* status);    [status:输出型参数——用于获取退出子进程的返回值]

处理退出的子进程,如果调用这个接口没有子进程已经退出,则会使父进程阻塞等待,直到有子进程退出

阻塞:为了完成一个功能我们发起一个调用,但是若当前不具备完成功能的条件,则调用等待

非阻塞:为了完成一个功能我们发起一个调用,但若当前不具备完成功能的条件,则调用立即报错返回

返回值:成功返回处理的退出子进程的pid,失败(比如没有子进程)返回-1

2.int  waitpid (int pid, int *status, int options);

返回值:成功返回退出子进程的pid,没有子进程退出返回0,失败(比如没有子进程)返回-1

wait与waitpid的区别:

(1)wait等待的是任意一个子进程的退出(wait是一个父进程假设有很多子进程,任意一个退出,都会处理后调用返回);waitpid可以等待指定的子进程,也可以等待任意一个子进程,通过第一个参数确定(第一个参数pid == -1表示等待任意)

(2)wait是一个阻塞接口(wait如果没有子进程退出,则会一直等待);waitpid可以默认阻塞,也可以设置为非阻塞,通过第三个参数确定(option == 0表示默认阻塞,option == WNOHANG表示非阻塞),非阻塞操作通常需要循环处理

3.获取子进程status (一个进程退出返回值只用了一个字节来保存)

Linux——进程创建、进程终止、进程等待、进程程序替换_第1张图片

 一个进程退出场景有两种:正常退出、异常退出

一个进程只有正常退出的时候返回值才有意义;若进程是异常退出,则返回值没有意义

因此在获取返回值之前,应先通过低七位判断进程是否是正常退出(正常退出则异常信号值为0;否则大于0)

判断一个程序是否正常退出:取出低七位;status & 0x7f == 0  正常退出   [WIFEXITED()]

如何取出返回值(低16位中的高8位):(status >> 8)& 0xff   ——因为返回值只用了一个字符,因此进程的返回值    [WEXITSTATUS]

系统调用接口出错后,如何获取错误原因?

#include

#include

char *strerror(errno);  根据错误编号获取文字信息——错误都是上一次系统调用接口使用错误的原因

perror(char *msg);直接打印上一次系统调用接口使用错误的原因

core dump——核心转储

指的是程序异常退出时,将退出前的程序运行信息保存下来(默认是关闭的)

四、进程程序替换

重新加载另一个程序到内存中,然后将现有的一个pcb的内存指针所指向的内存空间指向这个新的程序(更新页表映射信息),则这个现有的pcb就跑去调度这个新的程序了。

程序替换,给一个进程替换一个新的要调度运行的程序,并且因为这个进程调度的程序已经被替换,因此当运行完毕新的程序后会退出;原先的程序在程序替换以后的代码都不会被运行到(替换后相当于已经没有当前的代码了,只有新的程序)

如何替换:exec函数族

#include

int execl(const char *path, const char *arg, ...);//path—带路径的程序文件名称;arg/...表示程序的运行参数,逐个赋予,最终以NULL结尾
int execlp(const char *file, const char *arg, ...);//PATH环境变量指定了一些路径,execlp会去PATH环境变量指定的路径下查找程序文件
int execle(const char *path, const char *arg, ..., char *const envp[]);//通过envp参数自定义环境变量

int execv(const char *path, char *const arg[]);
int execvp(const char *file, char *const arg[]);
int execve(const char *path, char *const arg[], char *const envp[]);

l和 v的区别:程序运行参数的赋予方式不同

有没有p的区别:新的程序文件的名称是否需要带路径

有没有e的区别:是否自定义环境变量

你可能感兴趣的:(Linux)