1、僵尸进程
子进程退出,父进程不退出,且父进程不回收子进程的资源,此时子进程会变成僵尸进程
注意:
a.僵尸进程本身就是死掉的进程,无法再被kill;
b.僵尸进程是有危害的:占用进程号,占用进程调度块,占用cpu资源;
c.僵尸进程必须回收;
回收方式:
a.退出僵尸进程的父进程,僵尸进程的资源由内核自动回收;
b.wait/waitpid函数回收:阻塞形式会导致父进程无法完成自己的任务,非阻塞形式可能会收不到僵尸进程。
c.将wait/waitpid函数结合信号的方式回收:当子进程退出后,发送一个信号给父进程,通知父进程收尸
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
pid_t cpid=fork();
if(cpid>0){
while(1){
printf("chis is panent!\n");
sleep(1);
}
}else if(0==cpid){
exit(0);
}else{
perror("fork");
return -1;
}
return 0;
}
输出结果:
2、孤儿进程
退出父进程,子进程不退出,此时子进程被1号进程(init进程)收养。
注意:
a.孤儿进程脱离终端控制,运行在后端;
b.ctrl+c 无法杀死后端进程,孤儿进程可以用 kill-9 killall-9杀死;
c.孤儿进程是活着的进程,没有危害;
include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
pid_t cpid=fork();
if(0==cpid){
while(1){
printf("chis is child %d %d\n",getppid(),getpid());
sleep(1);
}
}else if(0<cpid){
exit(0);
}else{
perror("fork");
return -1;
}
return 0;
}
输出结果:
3、守护进程
a.守护进程是脱离于终端控制,且运行在后端的进程(孤儿进程);
b.守护进程不会将信息显示在任何终端上影响前端操作,也不会被终端产生的任何信息打断,例如(ctrl+c);
c.守护进程独立于控制终端,会周期性执行某个任务。(运行在死循环中)
d.守护进程用于:与操作系统启动相关的程序,大多数服务器都是用守护进程实现
步骤:
1):创建孤儿进程:所有任务在都运行在孤儿进程中,形式上脱离终端控制。
2):创建新的会话:使子进程完全独立。
a.setsid函数
功能:创建新的进程组,创建新的会话组;
pid_t setsid(void);
返回值:
成功:创建的会话组id sid
3):修改孤儿进程的运行目录为不可卸载的文件系统:例如根目录,或者其他不可删除的。
a.chdir函数
int chdir(const char *path);
chdir("/");
chdir("/tmp");
注:当前步骤往后,均运行在修改后的文件下面
4):重设文件权限掩码:守护进程一般保留文件原有权限 umask(0);
5):关闭所有从父进程继承过来的文件描述符;需要使用时候重新open;
for(int i=0;i<getdtablesize();i++){
close(i);
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
//1、创建孤儿进程
if(fork()==0){
//2、创建新的会话组
setsid();
//3、修改孤儿进程的运行目录为不可卸载的文件系统
chdir("/");
//4、重设文件掩码:守护进程一般保留文件原有权限
umask(0);
//5、关闭所有从父进程继承过来的文件描述符,需要使用的时候重新open
for(int i=0;i<getdtablesize();i++){
close(i);
}
while(1){
//守护进程的功能代码
sleep(1);
}
}
return 0;
}