forks代码在最下面.该文章主要针对fork()函数的分析
1.首先简述一下fork()函数的特性:调用一次,返回两次,父进程中返回子进程的ID,创建的子进程中返回的为0
2.这17个fork函数中,我把它们分类进行分析.
开始分析:
一.fork2,fork3为一类:该类单纯的应用了fork函数的性质,只要画出流程图,就能非常好理解了.下面以fork3为例简单分析:
void fork3()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("L2\n");
fork();
printf("Bye\n");
}
二.fork0,fork1,fork4,fork5为一类,该类以if语句限制不同进程的指令执行.以fork4为例子进行分析:
void fork4()
{
printf("L0\n");
if (fork() != 0) {
printf("L1\n");
if (fork() != 0) {
printf("L2\n");
}
}
printf("Bye\n");
}
文字分析:第一个if语句创建了一个子进程,并且如果是父进程则执行if内语句.如果是子进程则输出bye结束.第二个语句中又创建一个子进程,并且如果是父进程则执行if内的语句.如果是子进程则输出bye.
流程图:
(三)fork6单独为一类.
void cleanup(void) {
printf("Cleaning up\n");
}
void fork6()
{
atexit(cleanup);
fork();
exit(0);
}
分析:首先解释一下atexit函数,atexit函数调用后不返回,直接退出程序,其中的参数是void (*)(void).在该代码中,参数为cleanup,调用了cleanup函数.
执行结果:
(四)fork7,fork8为一类,该类用了无限循环语句,以fork8为例分析
void fork8()
{
if (fork() == 0) {
/* Child */
printf("Running Child, PID = %d\n",
getpid());
while (1)
; /* Infinite loop */
} else {
printf("Terminating Parent, PID = %d\n",
getpid());
exit(0);
}
}
分析:创建子进程后,子进程输出语句后无限循环,父进程正常终止.
执行结果:
(四)fork9,fork10,fork11为一类,该类主用了wait函数.
void fork9()
{
int child_status;
if (fork() == 0) {
printf("HC: hello from child\n");
exit(0);
} else {
printf("HP: hello from parent\n");
wait(&child_status);
printf("CT: child has terminated\n");
}
printf("Bye\n");
}
分析:先解释一下wait函数的作用:等待子进程结束后,父进程再继续执行.该代码中wait的参数child_status存放子进程的退出状态.fork9函数执行流程如下:创建子进程后,子进程和父进程同时进行下去,父进程执行到wait函数时,等待子进程结束再往下进行.
执行结果:
HC,HP的位置可以互换,但一定在CT的前面.
我们在来看一个更为复杂的例子fork11.
#define N 5
void fork11()
{
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0)
exit(100+i); /* Child */
for (i = N-1; i >= 0; i--) {
pid_t wpid = waitpid(pid[i], &child_status, 0);
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n",
wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminate abnormally\n", wpid);
}
}
分析:在第一个for语句中创建了五个子进程,在第二个for语句中使用了wait函数,并且如果每个子进程正常结束,则输出子进程的ID和结束状态.
执行结果:
(五).fork12,fork13,fork14,fork15,fork16分为一类.该类于信号有关.
先看一个简单的例子:fork12
define N 5
void fork12()
{
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0) {
/* Child: Infinite Loop */
while(1);
}
for (i = 0; i < N; i++) {
printf("Killing process %d\n", pid[i]);
kill(pid[i], SIGINT);
}
for (i = 0; i < N; i++) {
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n" ,wpid, WEXITSTAT
US(child_status));
else
printf("Child %d terminated abnormally\n", wpid);
}
}
分析:在第一个for循环中,创建了5个子进程,并且让for循环陷入死循环.第二个for循环则用kill函数给子进程发送SIGINT的信号,即为终止子进程(异常终止).最后一个for循环中,我们可以通过执行结果看到所有子进程都异常终止.
执行结果:
再来看一个更为复杂,我自己也没有弄清的例子:fork14
define N 5
int ccount = 0;
void child_handler(int sig)
{
int child_status;
pid_t pid = wait(&child_status);
ccount--;
printf("Received SIGCHLD signal %d for process %d\n", sig, pid); /* Unsafe */
fflush(stdout); /* Unsafe */
}
void fork14()
{
pid_t pid[N];
int i;
ccount = N;
signal(SIGCHLD, child_handler);
for (i = 0; i < N; i++) {
if ((pid[i] = fork()) == 0) {
sleep(1);
exit(0); /* Child: Exit */
}
}
while (ccount > 0);
}
分析:for循环中创建了五个子进程,子进程都休眠一秒后正常终止,一旦子进程终止,子进程就会发送信号给父进程,然后父进程接受信号转而执行child_handler函数.通过我的猜测,有五个子进程的终止,则有父进程会接收五个信号,从而调用child_hander函数五次.但实际情况为:
父进程只接收到一个信号!这使我感到迷惑,不过我初步猜测时因为信号发生过于频繁,后面的信号被忽略了,这只是个人观点,究竟时怎么样,我还没弄明白.
forks.c文件:
/*
- forks.c - Examples of Unix process control
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
/*
- fork0 - The simplest fork example
- Call once, return twice
- Creates child that is identical to parent
- Returns 0 to child process
- Returns child PID to parent process
*/
void fork0()
{
if (fork() == 0) {
printf(“Hello from child\n”);
}
else {
printf(“Hello from parent\n”);
}
}
/*
-
fork1 - Simple fork example
-
Parent and child both run same code
-
Child starts with identical private state
*/
void fork1()
{
int x = 1;
pid_t pid = fork();if (pid == 0) {
printf(“Child has x = %d\n”, ++x);
}
else {
printf(“Parent has x = %d\n”, --x);
}
printf(“Bye from process %d with x = %d\n”, getpid(), x);
}
/*
- fork2 - Two consecutive forks
- Both parent and child can continue forking
- Ordering undetermined
*/
void fork2()
{
printf(“L0\n”);
fork();
printf(“L1\n”);
fork();
printf(“Bye\n”);
}
/*
- fork3 - Three consective forks
- Parent and child can continue forking
*/
void fork3()
{
printf(“L0\n”);
fork();
printf(“L1\n”);
fork();
printf(“L2\n”);
fork();
printf(“Bye\n”);
}
/*
- fork4 - Nested forks in parents
*/
void fork4()
{
printf(“L0\n”);
if (fork() != 0) {
printf(“L1\n”);
if (fork() != 0) {
printf(“L2\n”);
}
}
printf(“Bye\n”);
}
/*
- fork5 - Nested forks in children
*/
void fork5()
{
printf(“L0\n”);
if (fork() == 0) {
printf(“L1\n”);
if (fork() == 0) {
printf(“L2\n”);
}
}
printf(“Bye\n”);
}
void cleanup(void) {
printf(“Cleaning up\n”);
}
/*
- fork6 - Exit system call terminates process
- call once, return never
*/
void fork6()
{
atexit(cleanup);
fork();
exit(0);
}
/*
- fork7 - Demonstration of zombies.
- Run in background and then perform ps
/
void fork7()
{
if (fork() == 0) {
/ Child /
printf(“Terminating Child, PID = %d\n”, getpid());
exit(0);
} else {
printf(“Running Parent, PID = %d\n”, getpid());
while (1)
; / Infinite loop */
}
}
/*
- fork8 - Demonstration of nonterminating child.
- Child still running even though parent terminated
- Must kill explicitly
/
void fork8()
{
if (fork() == 0) {
/ Child /
printf(“Running Child, PID = %d\n”,
getpid());
while (1)
; / Infinite loop */
} else {
printf(“Terminating Parent, PID = %d\n”,
getpid());
exit(0);
}
}
/*
-
fork9 - synchronizing with and reaping children (wait)
*/
void fork9()
{
int child_status;if (fork() == 0) {
printf(“HC: hello from child\n”);
exit(0);
} else {
printf(“HP: hello from parent\n”);
wait(&child_status);
printf(“CT: child has terminated\n”);
}
printf(“Bye\n”);
}
#define N 5
/*
-
fork10 - Synchronizing with multiple children (wait)
-
Reaps children in arbitrary order
-
WIFEXITED and WEXITSTATUS to get info about terminated children
*/
void fork10()
{
pid_t pid[N];
int i, child_status;for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0) {
exit(100+i); /* Child /
}
for (i = 0; i < N; i++) { / Parent */
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf(“Child %d terminated with exit status %d\n”,
wpid, WEXITSTATUS(child_status));
else
printf(“Child %d terminate abnormally\n”, wpid);
}
}
/*
-
fork11 - Using waitpid to reap specific children
-
Reaps children in reverse order
*/
void fork11()
{
pid_t pid[N];
int i;
int child_status;for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0)
exit(100+i); /* Child */
for (i = N-1; i >= 0; i–) {
pid_t wpid = waitpid(pid[i], &child_status, 0);
if (WIFEXITED(child_status))
printf(“Child %d terminated with exit status %d\n”,
wpid, WEXITSTATUS(child_status));
else
printf(“Child %d terminate abnormally\n”, wpid);
}
}
/*********
- Signals
*********/
/*
-
fork12 - Sending signals with the kill() function
*/
void fork12()
{
pid_t pid[N];
int i;
int child_status;for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0) {
/* Child: Infinite Loop */
while(1)
;
}
for (i = 0; i < N; i++) {
printf(“Killing process %d\n”, pid[i]);
kill(pid[i], SIGINT);
}for (i = 0; i < N; i++) {
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf(“Child %d terminated with exit status %d\n”,
wpid, WEXITSTATUS(child_status));
else
printf(“Child %d terminated abnormally\n”, wpid);
}
}
/*
- int_handler - SIGINT handler
/
void int_handler(int sig)
{
printf(“Process %d received signal %d\n”, getpid(), sig); / Unsafe */
exit(0);
}
/*
-
fork13 - Simple signal handler example
*/
void fork13()
{
pid_t pid[N];
int i;
int child_status;signal(SIGINT, int_handler);
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0) {
/* Child: Infinite Loop */
while(1)
;
}for (i = 0; i < N; i++) {
printf(“Killing process %d\n”, pid[i]);
kill(pid[i], SIGINT);
}for (i = 0; i < N; i++) {
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf(“Child %d terminated with exit status %d\n”,
wpid, WEXITSTATUS(child_status));
else
printf(“Child %d terminated abnormally\n”, wpid);
}
}
/*
- child_handler - SIGCHLD handler that reaps one terminated child
/
int ccount = 0;
void child_handler(int sig)
{
int child_status;
pid_t pid = wait(&child_status);
ccount–;
printf(“Received SIGCHLD signal %d for process %d\n”, sig, pid); / Unsafe /
fflush(stdout); / Unsafe */
}
/*
-
fork14 - Signal funkiness: Pending signals are not queued
*/
void fork14()
{
pid_t pid[N];
int i;
ccount = N;
signal(SIGCHLD, child_handler);for (i = 0; i < N; i++) {
if ((pid[i] = fork()) == 0) {
sleep(1);
exit(0); /* Child: Exit */
}
}
while (ccount > 0)
;
}
/*
- child_handler2 - SIGCHLD handler that reaps all terminated children
/
void child_handler2(int sig)
{
int child_status;
pid_t pid;
while ((pid = wait(&child_status)) > 0) {
ccount–;
printf(“Received signal %d from process %d\n”, sig, pid); / Unsafe /
fflush(stdout); / Unsafe */
}
}
/*
-
fork15 - Using a handler that reaps multiple children
*/
void fork15()
{
pid_t pid[N];
int i;
ccount = N;signal(SIGCHLD, child_handler2);
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0) {
sleep(1);
exit(0); /* Child: Exit */}
while (ccount > 0) {
pause();
}
}
/*
- fork16 - Demonstration of using /bin/kill program
*/
void fork16()
{
if (fork() == 0) {
printf(“Child1: pid=%d pgrp=%d\n”,
getpid(), getpgrp());
if (fork() == 0)
printf(“Child2: pid=%d pgrp=%d\n”,
getpid(), getpgrp());
while(1);
}
}
/*
- Demonstration of using ctrl-c and ctrl-z
*/
void fork17()
{
if (fork() == 0) {
printf(“Child: pid=%d pgrp=%d\n”,
getpid(), getpgrp());
}
else {
printf(“Parent: pid=%d pgrp=%d\n”,
getpid(), getpgrp());
}
while(1);
}
int main(int argc, char *argv[])
{
int option = 0;
if (argc > 1)
option = atoi(argv[1]);
switch(option) {
case 0: fork0();
break;
case 1: fork1();
break;
case 2: fork2();
break;
case 3: fork3();
break;
case 4: fork4();
break;
case 5: fork5();
break;
case 6: fork6();
break;
case 7: fork7();
break;
case 8: fork8();
break;
case 9: fork9();
break;
case 10: fork10();
break;
case 11: fork11();
break;
case 12: fork12();
break;
case 13: fork13();
break;
case 14: fork14();
break;
case 15: fork15();
break;
case 16: fork16();
break;
case 17: fork17();
break;
default:
printf(“Unknown option %d\n”, option);
break;
}
return 0;
}