深入理解计算机系统系列08

前言

这学期事情很多,先是打了两个比赛(纷纷菜掉 ,吐血明年再来),然后就是交各种材料,之后就是组队伍,做项目,接手新的比赛,又因此买了一块移动硬盘,弄好了比赛的模拟的环境(随身携带操作系统,真是厉害),然后做完计划,寒假和下学期安排的明明白白,唉,也到了必须冲一把的时候了。废话就不多说了,直接讲吧。

fork函数

前面讲了关于fork函数的一些面试题,这里讲下关于fork函数的相关的知识

getpid()

返回当前的进程PID

waitpid(pid_t pid,int *statusp,int options)

PID:
pid>0时只等待ID为pid的子进程结束
pid=-1时等待其所有的子进程中任何一个结束
options:
options=0,挂起父进程,等待子进程结束。返回子进程PID
options=WNOHANG时,父进程不挂起没有子进程结束的话,返回0,否则返回子进程的PID

wait(&status)
等价于waitpid(-1,&status,0)

atexit()

在进程结束调用exit()时候调用,括号内的函数,调用顺序和登记顺序相反,类似栈

#include "csapp.h"
int main()
{
	int i;
	
	for(i=0;i<2;++i)
		Fork();
	printf("hello\n");
	exit(0);
}

共有4个hello
在这里插入图片描述
进程图如下
在这里插入图片描述
题目2:

#include "csapp.h"
void doit()
{
    Fork();
    Fork();
    printf("hello\n");
    return;
}

int main()
{
    doit();
    printf("hello\n");
    exit(0);
}
结果如下

在这里插入图片描述
在这里插入图片描述
下面输出是:

#include "csapp.h"

int main()
{
    int x = 3;

    if (Fork() != 0)
	printf("x=%d\n", ++x);

    printf("x=%d\n", --x);
    exit(0);
}
只要满足拓扑排序就可
可能的结果有:
1.
x=5
x=4
x=3
2.
x=4
x=2
x=3
3.
x=2
x=4
x=3
进程图

![在这里插入图片描述](https://img-blog.csdnimg.cn/2019120712220512.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
题目

/* $begin forkprob5 */
#include “csapp.h”

void doit()
{
if (Fork() == 0) {
Fork();
printf(“hello\n”);
exit(0);
}
return;
}

int main()
{
doit();
printf(“hello\n”);
exit(0);
}
/* $end forkprob5 */

总共有三个hello
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207122531185.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
题目

/* $begin forkprob5 */
#include “csapp.h”

void doit()
{
if (Fork() == 0) {
Fork();
printf(“hello\n”);
return;
}
return;
}

int main()
{
doit();
printf(“hello\n”);
exit(0);
}
/* $end forkprob5 */

同理5个hello
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207122659148.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
题目:

/* $begin forkprob7 */
#include “csapp.h”
int counter = 1;

int main()
{
if (fork() == 0) {
counter–;
exit(0);
}
else {
Wait(NULL);
printf(“counter = %d\n”, ++counter);
}
exit(0);
}
/* $end forkprob7 */

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207122813220.png)
进程图:
此题目注意wait()的用法

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207123304974.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)

/* $begin forkprob2 */
#include “csapp.h”

void end(void)
{
printf(“2”); fflush(stdout);
}

int main()
{
if (Fork() == 0)
atexit(end);
if (Fork() == 0)
printf(“0”);fflush(stdout);
else
printf(“1”);fflush(stdout);
exit(0);
}
/* $end forkprob2 */


可能输出就是拓扑排序的值域
112002、102120、100212多选题中这几个选项都是对的
进程图
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019120712394951.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
题目

#include “csapp.h”

/* $begin forkprob8 */
void foo(int n)
{
int i;

for (i = 0; i < n; i++) 
Fork();
printf("hello\n");
exit(0);

}
/* $end forkprob8 */

int main(int argc, char **argv)
{
if (argc < 2) {
printf(“usage: %s \n”, argv[0]);
exit(0);
}
foo(atoi(argv[1]));
exit(0);
}

结果为2^n
每个循环都会进行fork出来两个进程,每个进程printf一次得到最后的结果
题目:

#include “csapp.h”

/* $begin waitprob3 /
int main()
{
if (fork() == 0) {
printf(“a”);
exit(0);
}
else {
printf(“b”);
waitpid(-1, NULL, 0);
}
printf(“c”);
exit(0);
}
/
$end waitprob3 */


最后的结果一定是abc
因为当没有换行符的时候,printf的输出,其实并没有马上输出,而在缓冲区内
所以即使父进程先进行printf b的操作,b仍在缓冲区中等到a先打印完,
题目

void fork3()
{
printf(“L0\n”);
pid_t pid;
pid=fork();
if(pid0)printf(“l1\n”);
else printf(“L1\n”);
pid =fork();
if(pid
0) printf(“l2\n”);
else printf(“L2\n”);
pid=fork();
if(pid==0) printf(“bye\n”);
else printf(“Bye\n”);
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207124954939.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
题目:

void fork5()
{
printf(“L0\n”);
if (fork() == 0) {
printf(“L1\n”);
if (fork() == 0) {
printf(“L2\n”);
}
}
printf(“Bye\n”);
}

进程图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207125439872.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
题目(注意与上面题目的细小的差别)

void fork4()
{
printf(“L0\n”);
if (fork() != 0) {
printf(“L1\n”);
if (fork() != 0) {
printf(“L2\n”);
}
}
printf(“Bye\n”);
}

注意这函数
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207125620939.png)
题目:

void cleanup(void) {
printf(“Cleaning up\n”);
}
void fork6()
{
atexit(cleanup);
fork();
exit(0);
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207125834151.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
机器运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207130007121.png)
题目:

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 */
}
}


父进程进入死循环,子进程结束以后进入僵死转态
而下面为父进程结束,子进程变成孤儿进程,进入死循环
可以用kill -9命令杀死
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207131715645.png)

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);
}
}


void fork9()
{
int child_status;

if (fork() == 0) {
printf("HC: hello from child\n");
//sleep(10);
    exit(0);
} else {
    //sleep(5);
printf("HP: hello from parent\n");
wait(&child_status);
printf("CT: child has terminated\n");
}
printf("Bye\n");

}

下面两个注意区别
题目:

#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);
}

}

首先进行第一个fork,而后在 第一个for循环看做子进程,第二个for循环看做父进程
父进程中的pid数组中存放了所有的子进程PID,for进行wait,随机找一个结束的子进程返回它的exit的值并回收该进程,打印出来
wpid时候wait函数执行成功时返回子进程的ID号,WEXITSTATUS(child_status)返回子进程exit的值
运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207130952439.png)
而下面一个题目:

#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);
}

}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019120713105935.png)
解释下:这里调用的是waitpid,并且PID给了指定的值
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191207131444820.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNTkzNDA0,size_16,color_FFFFFF,t_70)
# 后言
很多事情做的不好,故而惩罚自己今天饿着不吃饭,作为警醒
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值