前言
这学期事情很多,先是打了两个比赛(纷纷菜掉 ,吐血明年再来),然后就是交各种材料,之后就是组队伍,做项目,接手新的比赛,又因此买了一块移动硬盘,弄好了比赛的模拟的环境(随身携带操作系统,真是厉害),然后做完计划,寒假和下学期安排的明明白白,唉,也到了必须冲一把的时候了。废话就不多说了,直接讲吧。
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(pid0) 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)
# 后言
很多事情做的不好,故而惩罚自己今天饿着不吃饭,作为警醒