进程控制:创建、退出、等待、替换
创建: pid_t fork();–通过复制父进程创建一个子进程–父子进程代码共享,数据独有
返回值:错误返回-1,对于父进程返回值大于0-子进程的pid,对于子进程返回0
写实拷贝技术:创建子进程后,子进程与父进程各自有自己的虚拟地址空间,但是数据映射的实际上是同一块物理内存,等到内存发生改变的时候为子进程重新开辟一块独立的空间,保存子进程的数据(保持进程独立性)
提高fork创建子进程的效率
pid_t vfork(void)--通过复制父进程创建一个子进程-父子进程共用虚拟地址空间
创建子进程后,父进程会阻塞直到子进程 exit退出或者(程序替换)之后才会运行
共用同一个虚拟地址空间,同时运行会造成栈混乱
vfork创建的子进程不能在main函数中return退出
进程退出:退出一个进程
代码如下:
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 void fun(){
5 exit(0);//_exit(0);
6 }
7 int main()
8 {
9 printf("nihao");
10 sleep(2);
11 fun();
12 printf("-------\n");
13 return 0;
14 //exit(0);
15 }
进程的退出返回值: 正常退出:通过三种退出方式退出的进程(结果是否符合预期)
异常退出:程序因为某些错误异常崩溃退出
进程的返回值,实际上只使用了一个字节进行保存
概念:父进程等待子进程的退出,获取退出子进程的返回值,释放退出子进程的资源–>为了避免产生僵尸进程
操作:
pid_t wait(int *status);--阻塞函数
status:一个整型空间的地址,用于获取退出子进程的返回值
返回值:成功返回退出子进程的pid,失败返回-1;
等待任意一个子进程的退出,如果当前没有子进程退出则一直阻塞等待
只要有退出的子进程,这个接口就会立即进行处理后返回
阻塞:为了完成一个功能,发起一个调用,若当前不具备完成条件,则一直等待
非阻塞:为了完成一个功能,发起一个调用,若当前不具备完成条件,则立即返回
代码如下:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<sys/wait.h>
5 int main()
6 {
7 pid_t pid = fork();
8 if(pid < 0){
9 perror("fork error");
10 exit(-1);
11 }else if(pid == 0){
12 //child
13 sleep(5);
14 exit(0);
15 }else{
16 //parents
17 int childpid = wait(NULL);
18 printf("%d----%d\n",pid,childpid);
19 while(1)
20 sleep(1);
21 }
22 return 0;
23 }
pid_t waitpid(pid_t pid, int *status, int options);
可以等待任意一个子进程退出,也可以只等待指定的子进程退出
可以阻塞等待子进程退出,也可以非阻塞等待子进程退出
退出子进程返回值/wait的参数获取到的值:status
一个程序在运行中,如果产生了某种错误(比如内存访问错误)系统就会给进程发送一个指定的信号表示进程出现了某个错误事件,收到这个信号后,进程(崩溃)退出
异常信号退出值为0,表示进程正常退出,非0表示异常退出
代码转换:1.判断进程是否正常退出;2.获取退出的实际返回值
status & 0x7f == 0; (status >> 8) 0xff
程序替换:替换一个进程正在调度运行的程序,程序替换,只是替换了运行的程序,而pcb中也只是重新初始化了一些信息(虚拟地址空间,页表……)
在一个进程中执行程序替换接口,就能实现改变当前调用进程运行的程序
exec函数族:一个系统调用接口+五个库函数
extern char **environ;
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 execvpe(const char *file, char *const argv[],char *const envp[]);
第一个参数是新的程序文件路径名,第二个参数是程序运行参数,第三个参数是环境变量
exec函数有p时,程序文件若是命令程序可以不用带路径默认去path环境变量指定的路径下找程序
带p的函数,常用于执行替换命令程序时使用
exec函数有e时,表示由我们自己设定环境变量,否则默认使用原有环境变量
代码如下:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/wait.h>
4 #include<unistd.h>
5 int main()
6 {
7 pid_t pid = fork();
8 if(pid < 0){
9 perror("fork error");
10 exit(-1);
11 }else if(pid == 0){
12 execlp("ls","ls","-l",NULL);
13 perror("程序替换失败");
14 exit(0);
15 }
16 wait(NULL);
17 printf("子进程已经退出\n");
18 return 0;
19 }