创建进程有两种方式,一是由操作系统创建;二是由父进程创建。操作系统创建的进程,它们之间是平等的,一般不存在资源继承关系。而由父进程创建的进程(子进程),它们和父进程存在隶属关系。子进程又可以创建进程,形成一个进程家族。
系统调用fork是创建一个新进程的唯一方法。进程调用fork函数就创建了一个子进程。
创建了一个子进程之后,父进程和子进程争夺CPU,抢到CPU者执行,另外一个挂起等待。若要父进程等待子进程执行完毕后再继续执行,可以在fork操作之后调用wait或waitpid。
fork函数
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
fork()函数调用后有2个返回值,调用一次,返回两次。成功调用fork函数后,当前进程实际上已经分裂为两个进程,一个是原来的父进程,另一个是刚刚创建的子进程。fork()函数的2个返回值,一个是父进程调用fork函数后的返回值,该返回值是刚刚创建的子进程的ID;另一个是子进程中fork函数的返回值,该返回值是0。这样可以用返回值来区分父、子进程。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
main()
{
pid_t pid;
char *msg;
int k;
pid=fork();
switch(pid){
//子进程执行部分
case 0:
msg="Child process is running.\n";
k=3;
break;
case -1:
perror("Process creation failed.\n");
break;
//父进程执行部分
default:
msg="Parent process is running.\n";
k=5;
break;
}
//父子进程共同执行部分
while(k>0){
puts(msg);
sleep(1);
k--;
}
}
运行结果:
上例中子进程输出3条消息,父进程输出5条消息。执行子进程和父进程时打印出的消息是不一样的。从输出可以看出父子进程交替进行。
注意:父子进程终止的先后顺序不同会产生不同的结果。
(1)在子进程退出前父进程先退出,则系统会让init进程接管子进程。
(2)当子进程先于父进程终止,而父进程又没有调用wait函数等待子进程结束,子进程进入僵尸状态,并且会一直保持下去除非系统重启。子进程处于僵尸状态时,内核只保存该进程的一些必要信息以备父进程所需。此时子进程始终占用着资源,同时也减少了系统可以创建的最大进程数。如果子进程先于父进程终止,且父进程调用了wait或waitpid函数,则父进程会等待子进程结束。
(3)在Linux下,可以简单地将SIGCHLD信号的操作设为SIG_IGN,这样当子进程结束时就不会称为僵尸进程。