linux进程(02)

xiaoxiao2021-02-28  20

fork & vfork

fork:用于创建进程,进程创建成功时,子进程返回0;创建失败时,返回-1;父进程返回子进程的id号 fork:除了进程的id号不同,父子进程的内容一样,执行顺序不同;一般情况要满足僵进程,借助wait()或者waitpid()函数 vfork:由于父进程主要是为了创建子进程,若用fork创建时,会造成资源的浪费;因此,fork应用而生。 vfork:父子进程,共享内存空间,vfork调用exec家族或exit函数满足子进程先执行。

例子

fork

1 #include<stdio.h> 2 #include<unistd.h> 3 int main() 4 { 5 pid_t pid; //创建进程 6 pid = fork(); //父进程 7 if(pid>0) 8 { 9 printf("Parent Wait...\n"); 10 //sleep(4); //阻塞等待子进程先执行 11 int status; 12 wait(&status); 13 printf("This is Parent\n"); 14 } //子进程 15 else if(pid == 0) 16 { 17 printf("Child Sleep...\n"); 18 sleep(2); 19 printf("This is Child\n"); 20 } 21 else 22 { 23 perror("fork"); 24 } 25 return 0; 26 }

vfork

#include<stdio.h> int main() { //内存共享 pid_t pid = vfork(); if(pid>0) { printf("Parent id = %d\n",getpid()); } else if(pid == 0) { printf("Child id=%d\n",getpid()); //正常退出 exit(0); } else { perror("vfork");} }

fork与vfork

1 #include<stdio.h> 2 #include<unistd.h> 3 int main() 4 { 5 int i=100; //创建进程,子进程复制父进程的内存空间 6 pid_t pid=fork(); 7 if(pid>0) 8 { 9 printf("Parent i=%d\n",i); 10 } 11 else if(pid == 0) 12 { 13 int i=10; 14 printf("Child i=%d\n",i); 15 } 16 else 17 { 18 perror("fork"); 19 } 20 21

result

Child i=10; Parent i=100; 执行的路线不同,i的值不同

1 #include<stdio.h> 2 #include<unistd.h> 3 #include<stdlib.h> 4 int main() 5 { 6 int i=100; //创建进程,数据共享 7 pid_t pid=vfork(); 8 if(pid == 0) 9 { 10 i=10; 11 printf("Child i=%d\n",i); 12 exit(0); 13 } 14 else if(pid > 0) 15 { 16 printf("Parent i=%d\n",i); 17 } 18 else 19 { 20 perror("fork"); 21 }

result :

Child i=10 Parent i=10,父进程等待子进程结束后执行,并且父进程和子进程共享内存空间

wait & waitpid

wait:父进程等待自己的一个直系的、提前执行的子进程,返回等待进程的id号

#include<stdio.h> #include<sys/wait.h> #include<unistd.h> int main() { pid_t pid = fork(); if(pid>0) { pid = fork(); // 0 号进程 if(pid>0) { printf("This is 0=[%d]\n",getpid()); int status; pid_t wait_res=wait(&status); printf("wait_res = %d\n",wait_res); if(IFEXITED(status)) { printf(" Child is ok finish.\n"); } else printf("Child is error finish.\n"); } //2 号进程 else if(pid == 0) { sleep(2); printf("This is 2=[%d]\n",getpid()); } } else if(pid == 0) { pid = fork(); //1号进程 if(pid>0) { sleep(5); printf("This is 1=[%d]\n,getpid()"); } //号进程 else if(pid==0) { printf("This is 3=[%d]\n",getpid()); } } else { perror("fork"); } return 0; }

进程之间的关系:

结果:

分析:父进程等待直系子进程,1号和2号进程,1号进程休眠5s,2号进程休眠1s,因此等待的是2号进程。因此,wait函数返回2号进程的id号

waitpid:父进程等待自己的一个直系的、指定的一个子进程,返回等待的进程的id号

#include<stdio.h> #include<sys/wait.h> #include<unistd.h> int main() { pid_t pid = fork(); if(pid>0) { //子进程的id号 pid_t g_pid = pid; pid = fork(); // 0 号进程 if(pid>0) { printf("This is 0=[%d]\n",getpid()); int status; pid_t wait_res=waitpid(,g_pid,&status,); printf("wait_res = %d\n",wait_res); if(IFEXITED(status)) { printf(" Child is ok finish.\n"); } else printf("Child is error finish.\n"); } //2 号进程 else if(pid == 0) { sleep(2); printf("This is 2=[%d]\n",getpid()); } } else if(pid == 0) { pid = fork(); //1号进程 if(pid>0) { sleep(5); printf("This is 1=[%d]\n,getpid()"); } //号进程 else if(pid==0) { printf("This is 3=[%d]\n",getpid()); } } else { perror("fork"); } return 0; }

分析:即使等待的2号进程时间长,1号进程时间短;但由于是指定等待了2号进程,返回2进程的id.

exec家族:

作用:在子进程中去调用其他的函数 ,进程的id号不会发生改变,只是将子进程中的代码进行了替换。

方式:路径+指针数组 来实现

在 函数 execl, execlp, 和 execle 中, const char *arg 以及 省略号 代表 的 参数 可被 视为 arg0, arg1, …, argn.,他们 合起来描述了 指向 null 结尾的 字符串 的 指针 列表, 即 执行程序 的 参数列表. 作为 约定, 第一个 arg 参数应该 指向 执行程序名自身. 参数列表 必须 用 NULL 指针 结束!

链表形式

//路径名 自身

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[]);

实现

ls

//不带环境变量 execl("/bin/ls",ls,NULL); //带有环境变量 path execlp("ls",ls,NULL);

数组形式

//路径名 自身

int execv( const char *path, char *const argv[]); int execvp( const char *file, char *const argv[]);

实现

ls

//不带path char *envp[]={"ls",NULL}; execv("/bin/ls",envp); //带 path char *envp[]={"ls",NULL}; execlp("ls",envp);

函数退出

1return ;函数返回时,父子进程都结束,返回给函数 2exit()函数,属于stdlib头文件中,只是子进程正常的结束,返回给操作系统 3、_exit()函数,属于unistd头文件,返回给了内核 3、abort(),异常退出

总结:

1、fork、vfork都可以创建进程,调用一次返回两次 2、fork要使用wait、waitpid,达到僵进程 3、vfork父子进程共享内存创建进程,exit()函数保证子进程先执行;exec家族处理问题 4、exec家族函数,在子进程中执行其他的操作

转载请注明原文地址: https://www.6miu.com/read-2631740.html

最新回复(0)