vfork函数也可以创建进程
vfork与fork的区别:
- vfork直接使用父进程存储空间,不拷贝;
- vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。
// fork
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if(pid > 0)
{
while(1)
{
printf("this is father pid, pid = %d\n", getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
printf("this is child pid, pid = %d\n", getpid());
sleep(1);
}
}
return 0 ;
}
// vfork,只有子进程运行
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = vfork();
if(pid > 0)
{
while(1)
{
printf("this is father pid, pid = %d\n", getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
printf("this is child pid, pid = %d\n", getpid());
sleep(1);
}
}
return 0 ;
}
// 达到相应的条件后,调用exit退出子进程,程序执行父进程,注意使用exit退出
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = vfork();
if(pid > 0)
{
while(1)
{
printf("this is father pid, pid = %d\n", getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
printf("this is child pid, pid = %d\n", getpid());
sleep(1);
cnt++;
if(cnt == 3)
{
exit(0);
}
}
}
return 0 ;
}
进程退出
-
正常退出
Main函数调用return;
进程调用exit(),标准C库;
进程调用_exit()或者 _Exit(),属于系统调用
补充:进程最后一个线程返回;最后一个线程调用pthread_exit
-
异常退出
调用abort;
当进程收到某些信号时,如ctrl+c;
最后一个线程对取消(cancellation)请求做出响应。
不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。
对上述任意一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit,_exit, _Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。
父进程等待子进程退出
为何要等待子进程退出?看子进程有没有干完活,继续进行接下来的工作。
父进程等待子进程退出,并收集子进程的退出;若子进程退出状态不被收集,将会变成僵死进程(僵尸进程)
宏 | 说明 |
---|---|
WIFEXITED(status) | 若为正常终止子进程返回的状态,则为真。对于这种情况可执行WEXITSTATUS(status),取子进程传送给exit,_exit或 _Exit参数的低8位 |
WIFSIGNALED(status) | 若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG(status),取使子进程终止的信号编号。另外,有些实现定义宏WCOREDUMP(status),若已产生终止进程的core文件,则它返回真。 |
WIFSTOPPED(status) | 若为当前暂停子进程的返回状态,则为真。对于这种情况,可执行WSTOPSIG(status),取使子进程暂停的信号编号 |
WIFCONTINUED(status) | 若在作业控制暂停后已经继续的子进程返回了状态,则为真。 |
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status = 10;
pid = fork();
if(pid > 0)
{
wait(&status);
printf("child exit, child status = %d\n", WEXITSTATUS(status));
while(1)
{
printf("this is father pid, pid = %d\n", getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
printf("this is child pid, pid = %d\n", getpid());
sleep(1);
cnt++;
if(cnt == 5)
{
exit(6);
}
}
}
return 0 ;
}
相关函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
/*
pid == -1 等待任一进程。就这一方面而言,waitpid与wait等效
pid > 0 等待其进程ID与pid相等的子进程
pid == 0 等待其组ID等于调用进程组ID的任一子进程
pid < -1 等待其组ID等于pid绝对值的任一子进程
*/
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
如果其所有子进程都还在运行,则阻塞。
如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
如果它没有任何子进程,则立即出错返回。
wait和waitpid的区别:wait使调用者阻塞,waitpid有一个选择,可以使调用者不阻塞。
孤儿进程:父进程如果不等待子进程退出,在子进程之前就结束自己的"生命",此时子进程叫做孤儿进程;Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status = 10;
pid = fork();
if(pid > 0)
{
printf("this is father pid, pid = %d\n", getpid());
}
else if(pid == 0)
{
while(1)
{
printf("this is child pid, pid = %d, father pid = %d\n", getpid(), getppid()); //getppid父进程的pid
sleep(1);
cnt++;
if(cnt == 5)
{
exit(6);
}
}
}
return 0 ;
}