计算机系统基础复习:forks10-17函数解析

fork

当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。

当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。

linux中fork()函数详解

信号

Linux 信号(signal)

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是将任务中断,挂起的状态,进程还存在,任务还没有结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值