多进程中,难免会出现父进程先于子进程退出或者子进程先于父进程退出,为此分为两种情况,若父进程先于子进程先退出,则子进程相当于孤儿进程;若子进程先于父进程先退出,则子进程相当于僵尸进程。
fork在
使用pid_t fork(void)函数创建子线程,若fork返回为-1,则调用失败;若fork返回为0,相当于是子线程;若fork大于0,则为父进程。
一、僵尸进程
例程
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fds[2];
pipe(fds);
pid_t pid;
pid=fork();
int i=0;
if(0==pid)
{
for(i=0;i<20;i++)
{
sleep(1);
printf("I'm child %d\n",i);
}
}
else
{
for(i=0;i<30;i++) //父进程调用时间大于子进程
{
sleep(1);
printf("I'm farmer %d\n",i);
}
}
if(pid==0)
{
printf("child exit!\n");
}
else
{
printf("farmer exit!\n");
}
return 0;
}
因子进程先于父进程退出,则出现,进程状态为Z+
machine~$:ps au|grep fork
1000 5282 0.0 0.0 4168 352 pts/3 S+ 14:23 0:00 ./fork_test
1000 5283 0.0 0.0 4168 88 pts/3 S+ 14:23 0:00 ./fork_test
1000 5287 0.0 0.0 13616 944 pts/4 S+ 14:23 0:00 grep --color=auto fork
machine~$:ps au|grep fork
1000 5282 0.0 0.0 4168 352 pts/3 S+ 14:23 0:00 ./fork_test
1000 5283 0.0 0.0 0 0 pts/3 Z+ 14:23 0:00 [fork_test]
1000 5289 0.0 0.0 13616 944 pts/4 S+ 14:23 0:00 grep --color=auto fork
fengweilong@machine~$:
解决方法(使用信号量SIGCHLD):
void fork_handler(int sig)
{
printf("child PID is end!\n");
int state;
waitpid(-1,state,WNOHANG);
}
struct sigaction act;
act.sa_handler = fork_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD,&act,0);
二、孤儿进程
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fds[2];
pipe(fds);
pid_t pid;
pid=fork();
int i=0;
if(0==pid)
{
for(i=0;i<30;i++)
{
sleep(1);
printf("I'm child %d\n",i);
}
}
else
{
for(i=0;i<20;i++) //子进程调用时间大于父进程
{
sleep(1);
printf("I'm farmer %d\n",i);
}
}
if(pid==0)
{
printf("child exit!\n");
}
else
{
printf("farmer exit!\n");
}
return 0;
}
父进程退出时,通知子进程,利用进程间通讯,方式有信号、信号量、共享内存、消息队列、管道和套接字。其中使用的是管道。解决方法:
#include
#include
#include
#include
#include
#include
#include
void fork_handler(int sig)
{
printf("child PID is end!\n");
int state;
waitpid(-1,state,WNOHANG);
}
void *read_error(void *arg)
{
int fd = *(int *)arg;
char buf[100];
printf("parent PID is %d,current PID is %d\n",getppid(),getpid());
while((-1 == read(fd,buf,sizeof(buf))) && EINTR == errno);//利用父进程退出后,管道退出,导致子进程再去读取时,导致退出循环,子进程返回
printf("parent PID is %d,current PID is %d\n",getppid(),getpid());
exit(-1);
}
int main()
{
struct sigaction act;
act.sa_handler = fork_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD,&act,0);
int fds[2];
pipe(fds);
pid_t pid;
pid=fork();
int i=0;
if(0==pid)
{
close(fds[1]);
pthread_t pthd;
pthread_create(&pthd,NULL,read_error,(void *)&fds[0]);
for(i=0;i<30;i++)
{
sleep(1);
printf("I'm child %d\n",i);
}
}
else
{
close(fds[0]);
for(i=0;i<20;i++)
{
sleep(1);
printf("I'm farmer %d\n",i);
}
}
if(pid==0)
{
printf("child exit!\n");
}
else
{
printf("farmer exit!\n");
}
return 0;
}
实验结果父进程退出后,子进程也一起退出:
/FORK_PID$:./fork
parent PID is 5291,current PID is 5292
I'm child 0
I'm farmer 0
I'm child 1
I'm farmer 1
I'm child 2
I'm farmer 2
。。。。
I'm child 18
I'm farmer 18
I'm child 19
I'm farmer 19
farmer exit!
parent PID is 1,current PID is 5292