1、僵尸进程和孤儿进程
僵尸进程: 当子进程退出时,父进程没有收回子进程资源(PCB),则子进程变为僵尸进程。
孤儿进程: 当父进程先于子进程结束,则子进程变为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程,领养孤儿进程。
//程序1 清理僵尸进程(回收子进程)
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
//[root@localhost ~]# man 2 wait <查看头文件>
int main(void)
{
pid_t pid, pid_c;//定义pid,pid_c变量
pid = fork();//调用1次,返回2次,在父进程中返回子进程ID号,在子进程中返回0
if (pid>0)//父进程
{
while (1)
{
printf("I am the parent %d\n", getpid());//获取当前进程ID号
//回收子进程
//wait是一个阻塞函数,功能1-等待回收子进程资源,如果没有子进程,则返回-1
//功能2-为父进程提供手段,知道子进程是怎么死的
pid_c = wait(NULL);
printf(" pid_c %d\n", pid_c);//获取当前进程ID号
sleep(1);
}
}
else if (pid == 0)//子进程
{
printf("I am child %d\n", getpid());//获取当前进程ID号
sleep(10);//延时10s
}
else //进程创建出错
{
perror("fork\n");
exit(-1);
}
return 0;
}
终端命令程序执行效果:
2、用fork创建子进程后执行的是和父进程相同的程序,但有可能执行不同的代码分支,子进程往往要调用一种exec函数以执行另一个程序。
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。
注:调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
//程序2-1 子程序执行终端查看命令任务
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
//[root@localhost ~]# man 2 wait 查看头文件
int main(void)
{
printf("hello\n");//输出hello
execl("/bin/ls", "ls", "-l", NULL);//执行ls -l任务
printf("world\n");//输出world
return 0;
}
//程序2-2 另一种替换方式
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
//[root@localhost ~]# man 2 wait 查看头文件
int main(void)
{
pid_t pid;//定义pid变量
pid = fork();//调用1次,返回2次,在父进程中返回子进程ID号,在子进程中返回0
char *argv[]={"ls","-l",NULL};//字符指针赋值
if(pid > 0)//父进程
{
while (1)
{
printf("I am the parent %d\n", getpid());//获取当前进程ID号
sleep(1);
}
}
else if (pid == 0)//子进程
{
printf("I am child %d\n", getpid());//获取当前进程ID号
execv("/bin/ls",argv);
}
else
{
perror("fork\n");
exit(-1);
}
return 0;
}
终端命令程序执行效果:
//execl本意为去磁盘当中加载另一个可执行程序,用另一个程序段替换当前进程的代码段和数据段。(替换动作)
//程序3-1
#include <stdio.h>
int main(int argc,char *argv[])
{
int i=0;
while(i<argc)
{
printf("%s\n",argv[i++]);
}
return 8;
}
//程序3-2
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>//[root@localhost ~]# man 2 wait 查看头文件
int main(void)
{
printf("hello\n");
execl("/usr/lesson/dx1902/806/test1","./test1","xiaoxue","xiaomei","xiaoming",NULL);
printf("world\n");
return 0;
}
程序执行效果:
//程序4 打开浏览器
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
//[root@localhost ~]# man 2 wait //查看头文件
//[root@localhost ~]# which firefox --> /usr/bin/firefox
int main(void)
{
pid_t pid;//定义pid变量
pid = fork();//调用1次,返回2次,在父进程中返回子进程ID号,在子进程中返回0
if(pid > 0)//父进程
{
while (1)
{
printf("I am the parent %d\n", getpid());//获取当前进程ID号
sleep(1);//延时1s
}
}
else if (pid == 0)//子进程
{
printf("I am child %d\n", getpid());//获取当前进程ID号
//execl("/usr/bin/firefox","firefox","www.163.com",NULL);//法一
execlp("firefox","firefox","www.163.com",NULL);//法二
}
else
{
perror("fork\n");
exit(-1);
}
return 0;
}
//程序5 回收多个子进程
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
//[root@localhost ~]# man 2 wait //查看头文件
int main(void)
{
pid_t pid;//定义pid变量
int n = 3;
while (n--)
{
pid = fork();//调用1次,返回2次,在父进程中返回子进程ID号,在子进程中返回0
if (pid == 0)
{
break;
}
}
if (pid == 0)//子进程
{
printf("I am child %d\n", getpid());//获取当前进程ID号
sleep(3);//延时3s
}
else if (pid > 0)//父进程
{
printf("n= %d\n", n);//获取当前进程ID号
n++;
pid_t pid_c;//定义pid_c变量
while(1)
{
printf("I am the parent %d\n", getpid());//获取当前进程ID号
pid_c=waitpid(0,NULL,WNOHANG);
if (pid_c>0)
{
n++;
}
if (pid_c == -1)
{
continue;
}
else
{
printf("waite for the child %d\n", pid_c);
}
if (n == 3)
{
break;
}
sleep(1);
}
}
else
{
perror("fork\n");
exit(-1);
}
return 0;
}