fork:
当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。
当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。
信号:
10
#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))//如果子程序通过调用exit或return正常终止
printf("Child %d terminated with exit status %d\n",
wpid, WEXITSTATUS(child_status));//打印已终止子进程的PID和其退出码
else
printf("Child %d terminate abnormally\n", wpid);//打印已终止子进程的PID
}
}
11
*
* fork11 - Using waitpid to reap specific children使用waitpid获取特定子进程
* 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));//打印已终止的子进程的PID和退出码
else
printf("Child %d terminate abnormally\n", wpid);//打印已终止的子进程的PID
}
}
对比:10:
for (i = 0; i < N; i++) { /* Parent */
pid_t wpid = wait(&child_status);
<==>wait(-1,&child_status,0);//当等待集合中的一个子进程终止,立即返回。
11:
for (i = N-1; i >= 0; i--) {
pid_t wpid = waitpid(pid[i], &child_status, 0);
12
/*
* 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);//杀死进程pid[i],并发送信号给相应的进程。
}
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杀死,故WIFEXITED(child_status)都为假, terminated abnormally。
13
/*
* 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);/*当进程接收到一个类型为SIGINT的信号,就会调用int_handle程序。*/
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);
/*父进程用kill函数发送SIGINT信号给其子进程,子进程的signal函数接收到SIGINT信号,调用handler函数处理,并正常终止。*/
}
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));//正常终止:status0
else
printf("Child %d terminated abnormally\n", wpid);
}
}
14
/*
* 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--;
//当子进程都结束时,count=0=>父进程结束循环。
//如果子进程未全部结束,父进程会一直循环下去,已经结束的子进程会变成僵死进程。
printf("Received SIGCHLD signal %d for process %d\n", sig, pid); /* Unsafe */
fflush(stdout); /* Unsafe */
}
//signal函数接受到SIGCHILD信号,执行child_handler程序。
//当等待子集中的一个子程序终止时,count--,打印接受到的信号和相应的子进程。
/*
* 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 */
//Child:sleep结束,exit子进程正常终止,会给父进程发送一个SIGCHILD,17号信号。
//在父进程处理该信号之前,已终止的子进程发送的SIGCHILD信号->待处理信号。
//在任何时刻,一种类型至多只会有一个待处理信号,故剩余部分会被丢弃。
}
}
while (ccount > 0)
;
}
僵死进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵死进程。
15
/*
* 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) {//当5各子进程未全部退出时
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();
//让调用函数失眠,直到该进程收到一个信号。
//当子进程终止发出SIGCHILD信号给signal,调用child_handler2程序。
}
}
16
/*
* fork16 - Demonstration of using /bin/kill program
*/
void fork16()
{
if (fork() == 0) {
printf("Child1: pid=%d pgrp=%d\n",
getpid(), getpgrp());//getpgrp()取得目前进程所属的组识别码
if (fork() == 0)
printf("Child2: pid=%d pgrp=%d\n",
getpid(), getpgrp());
while(1);
}
}
子进程与父进程属于同一进程组。
17
/*
* 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);
}
Ctrl+c是强制中断程序的执行,杀死程序的进程;
Ctrl+z是将任务中断,挂起的状态,进程还存在,任务还没有结束。