赞
踩
fork是依次调用两次返回,分别返回在父进程和子进程中
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;
{由于嫌麻烦所以把Bye写成B}
void fork0()
{
if (fork() == 0) {
printf("Hello from child\n");
}
else {
printf("Hello from parent\n");
}
}
在这段代码中,fork()被执行后将创建与父进程相同的子进程,并返回参数。
注意,这里出现了小问题,父进程结束后shell就出来了,这是是因为父进程是当前shell命令执行的,它结束了,就返回了shell。后面是子进程继续打印信息。
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);
}
执行结果
这段代码中使用了getpid来查看进程的pid号以及查看父进程子进程中x修改的值,修改之前x的值是完全一样的。
void fork2()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("Bye\n");
}
如果不出意料输出结果将会是L0,L1,BYE,BYE,L1,BYE,BYE
进程之间一旦启动子进程,后续代码就会并发,没有先后顺序
void fork3()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("L2\n");
fork();
printf("Bye\n");
}
在fork2中我们看不大出来进程的顺序,理想顺序应该是L0,L1,L2,B,B,L2,B,B,L1,L2,B,B,L2,B,B如同二叉树的先序遍历。
但执行结果与我们有点差别是L0,L1,L2,B,B,L2,B,L1,L2,B,B,B,L2,B,B和。。。
原因就是进程之间一旦启动子进程,后续代码就会并发,没有先后顺序。试了好几次试出来两种,虽然没有先后顺序,但fork也是有顺序的,每一层之间的顺序是不可逆的。如:A,B.C,B为A子进程,C为B子进程,A执行之后不可能直接执行C,就是这个道理。
void fork4()
{
printf("L0\n");
if (fork() != 0) {
printf("L1\n");
if (fork() != 0) {
printf("L2\n");
}
}
printf("Bye\n");
}
该案例中由于有if的关系,父进程有L0,L1,L2,B,子进程只有一个B,还有一个二阶子进程有一个B。
void fork5()
{
printf("L0\n");
if (fork() == 0) {
printf("L1\n");
if (fork() == 0) {
printf("L2\n");
}
}
printf("Bye\n");
}
首先父进程输出L0,由于if中判断是否是子进程,所以直接输出B,进入一阶子进程,输出L1,B,执行fork但不进入if语句,进入二阶子进程输出L2,B,结束。
void cleanup(void) {
printf("Cleaning up\n");
}
void fork6()
{
atexit(cleanup);
fork();
exit(0);
}
函数名: atexit()
头文件:#include<stdlib.h>
功 能: 注册终止函数(即main执行结束后调用的函数)
功能很简单,就是在exit()的时候调用函数,我们可以知道exit()被调用两次,即父进程一次,子进程一次。
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 */
}
}
子进程结束但父进程不结束,导致shell出不来了,果断Ctrl+Z
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);
}
}
进程还在运行,但是shell出来了,看不出来运行,对于新手来说说不定就以为没了,但是!!!!
他在占内存啊喂。
打开 ps -ef,emmmmm,我哭了,他还在运行,我要kill它。
成功杀死=-=
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");
}
函数原型是
#include <sys/types.h>
#include <wait.h>
int wait(int *status)
函数功能是:
父进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
了解一下wait()他会让父进程等待子进程结束。但不可以乱用
#define N 5 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); } }
WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。
结束顺序不定。
父进程fork五次后,进入wait循环,子进程是直接执行exit的,他们无法fork()。
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); } }
在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞;
waitpid()并不等待在其调用之后的第一个终止的子进程,它有若干个选项,可以控制它所等待的进程;
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); } }
父进程fork五次后子进程一直处于循环之中,之后父进程杀死子进程,父进程等待子进程正常结束,结束异常。杀死顺序一定,而等待结束顺序不一定。
void int_handler(int sig) { printf("Process %d received signal %d\n", getpid(), sig); /* Unsafe */ exit(0); } 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); } }
kill子进程的时候产生了信号SIGINT,触发处理信号函数int_handler提前将子进程exit,所以结束不出现异常,正常结束。
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) ; }
SIGCHLD,在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程,按系统默认将忽略此信号,如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。
运行结果是只输出一行后不在输出也无法结束,似乎陷入了while循环之中
经过我笨拙的print参数发现SIGCHLD只被调用了一次?!为什么?
明明出现了五个exit()
这说明了挂起的信号没有入队
fork后父子进程的执行时不确定的,如果子进程在父进程调用Signal(SIGCHLD, sig_chld)之前退出,父进程不会受到SIGCHLD信号。
5个子进程退出,父进程不一定会收到5个信号,但是至少会收到一个。
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 */ } } 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(); } }
pause() 功能:让进程暂停直到信号出现。
该代码中,对于父进程能同时接受几个SIGCHLD,并不重要,只要有一个SIGCHLD能到达就OK,
产生SIGCHLD让父进程接受的目的是为了让父进程调用child——handler(),更切切的说是为了调用
wait()函数,而此时wait()处于while中,故会一直处理直到没有结束的子进程时,退出。
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);
}
}
getpgrp是一种函数,功能是用来取得目前进程所属的组识别码。
由此可见子进程的组识别码都是一样的。
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);
}
由该代码所见,所有子进程组识别码ID与父进程组识别码ID相同。
对于进程组ID,一般来说,一个进程在shell下执行,shell程序就将该进程的PID赋给该进程的进程组ID,从该进程派生的子进程都拥有父进程所属的进程组ID,除非父进程将子进程的所属组ID设置成与该子进程的PID一样。
/* * 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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。