HomeWork ( 一) P46:Interlude: Process API

2024-01-25 04:10

本文主要是介绍HomeWork ( 一) P46:Interlude: Process API,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

总的来说这一页的习题就是让你看懂,我们有哪些API!以及这些API最基本的调用方法和特性。

Homework (Code)

In this homework, you are to gain some familiarity with the process management APIs about which you just read. Don’t worry – it’s even more fun than it sounds! You’ll in general be much better off if you find as much time as you can to write some code5, so why not start now?

Questions

  1. Write a program that calls fork(). Before calling fork(), have the main process access a variable (e.g., x) and set its value to some- thing (e.g., 100). What value is the variable in the child process? What happens to the variable when both the child and parent change the value of x?

  2. Write a program that opens a file (with the open() system call) and then calls fork() to create a new process. Can both the child and parent access the file descriptor returned by open()? What happens when they are writing to the file concurrently, i.e., at the same time?

  3. Write another program using fork(). The child process should print “hello”; the parent process should print “goodbye”. You should try to ensure that the child process always prints first; can you do this without calling wait() in the parent?

  4. Write a program that calls fork() and then calls some form of exec() to run the program /bin/lsSee if you can try all of the variants of exec(), including execl(), execle(), execlp(), execv(), execvp(), and execvP(). Why do you think there are so many variants of the same basic call?

  5. Now write a program that uses wait() to wait for the child process to finish in the parent. What does wait() return? What happens if you use wait() in the child?

  1. Write a slight modification of the previous program, this time using waitpid() instead of wait(). When would waitpid() be useful?

  2. Write a program that creates a child process, and then in the child closes standard output (STDOUT FILENO). What happens if the child calls printf() to print some output after closing the descriptor?

  3. Write a program that creates two children, and connects the standard output of one to the standard input of the other, using the pipe() system call.

解答
第 1/2 题 : 父进程和子进程共享“变量”、“文件”、“缓冲区”,但是文件这里是个坑,第一题变量就不说了,第二题中 fwrite 和 write的差别会导致输出不一样,比如
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>int main(int argc, const char * argv[]) {char *hello="hello\n";char *world="world\n";char *welcome = "welcome\n";FILE *fp;if((fp  = fopen("/Users/air/Desktop/OS3pieces/Process API Program in The Book/HomeWork2/test.txt", "at+"))== NULL){printf("OPEN ERROR!");return 0;}if(fwrite(welcome, strlen(welcome), 1, fp) < 1)printf("WRITE ERROR");int pid = fork();if(pid  < 0){printf("Fork created error!\n");}else if(pid == 0){printf("I am the child, my pid is %d\n",(int)getpid());if(fwrite(hello, strlen(hello), 1, fp) < 1)printf("WRITE ERROR");}else{printf("I am the parent, my child is %d, my own pid is %d\n", pid, (int)getpid());if(fwrite(world, strlen(world), 1, fp)< 1)printf("WRITE ERROR");}fclose(fp);return 0;
}
输出为:
welcome
world
welcome
hello

因为子进程的缓冲区内已经有了welcome,所以打印的时候会一起打印出来;

比如:把 fwrite 换成了 write之后:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>int main(int argc, const char * argv[]) {char *hello="hello\n";char *world="world\n";char *welcome = "welcome\n";FILE *fp;if((fp  = open("/Users/air/Desktop/OS3pieces/Process API Program in The Book/HomeWork22/test.txt", O_WRONLY))== NULL){printf("OPEN ERROR!");return 0;}if(write(fp,welcome, strlen(welcome)) < 1)printf("WRITE ERROR");int pid = fork();if(pid  < 0){printf("Fork created error!\n");}else if(pid == 0){printf("I am the child, my pid is %d\n",(int)getpid());if(write(fp,hello, strlen(hello)) < 1)printf("WRITE ERROR");}else{printf("I am the parent, my child is %d, my own pid is %d\n", pid, (int)getpid());if(write(fp,world, strlen(world))< 1)printf("WRITE ERROR");}fclose(fp);return 0;
}
输出为:
welcome
hello
world


再奉上一道腾讯的校招笔试题:分别打印多少个 “-” 和 “-\n”?

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>int main(){for(int i=0;i<2;i++){fork();printf("-");}return 0;
}
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>int main(){for(int i=0;i<2;i++){fork();printf("-\n");}return 0;
}

我觉得这里还是有些坑要小心点的。


第 3  题:  不使用wait()函数,让子程序先完成。 这道题很开放哈,我自己的做法是这样的,再父进程中再创建fork(), 代码如下:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>int main(int argc, const char * argv[]) {int pid = fork();if(pid  < 0){printf("Fork created error!\n");}else if(pid == 0){printf("I am the child, my pid is %d\n",(int)getpid());printf("Hello\n");}else{int id = fork(); //就是在父进程中,再次调用fork函数,那么fork函数执行完父程序后什么也没打印,然后再执行第一个子程序 hello ,再执行第二个子程序 goodbyeif(id == 0){printf("goodbye\n");}//int wc = wait(NULL); Instead of using wait function,make sure that the child proces excute first.printf("I am the parent, my child is %d, my own pid is %d\n", pid, (int)getpid());}return 0;
}
第 4 题:用exec族的6个函数实现一个功能,我觉得这位同学写的不错,直接就贴上来吧,看懂了自己肯定是能写的。

            https://blog.csdn.net/zjwson/article/details/53337212 点击打开链接

           代码仿照了一下,这个真的是超级超级基本的函数额,一定要注意的是路径的问题,当然记不住回去看看文档就好了,shell里文档的命令是:

man execl      


第 5 题:是关于wait() 函数的返回值的。同样有很详细的解答了已经:

           https://www.cnblogs.com/black-mamba/p/6886434.html  点击打开链接

            那么子进程中使用wait()当然是返回 -1 啦~~(如果子进程中没有再使用fork函数的话)

第 6 题:是关于waitpid () 函数的返回值的。同样有很详细的解答了已经:            

           https://blog.csdn.net/roland_sun/article/details/32084825 点击打开链接

           再父进程里试一下不同的 options 就可以看到父子进程不同的执行顺序。

           比如 options = WNOHANG, (这个WNOHANG肯定是个宏啦 - - 不知道是1 还是多少,我不想去看),那就还是父进程先行啦,都说了no hang 了!!不等你啊!!

int main(int argc, const char * argv[]) {int pid = fork();if(pid  < 0){printf("Fork created error!\n");}else if(pid == 0){printf("I am the child, my pid is %d\n",(int)getpid());}else{//wait(); 只要有一个进程终止,wait就会返回。也就是说只要wait接收到一个SIGCHLD信号,wait()就会返回。//对于两个或多个子进程的情况,需要调用wait两次或多次;//c. 如果它没有任何子进程,则立即出错返回;waitpid(pid,NULL,WNOHANG);//1、waitpid可等待一个特定的进程,而wait则返回任一终止子进程的状态//2、waitpid提供了一个wait的非阻塞版本//3、waitpid支持作业控制printf("I am the parent, my child is %d, my own pid is %d\n", pid, (int)getpid());}return 0;
}

第 7 题:关掉了STDOUT_FILENO之后,fprintf 当然是打印不出啦!!但是编译还是没问题的。

第 8 题:关于pipe ()函数,觉得这篇很棒,https://blog.csdn.net/skyroben/article/details/71513385 点击打开链接

      这张图真的太棒了:

 一秒看懂pipe!!         

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>int main(int argc, const char * argv[]) {int fd[2];int ret = pipe(fd);//fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端if(ret == -1){perror("pipe error\n");exit(1);}pid_t pid = fork();if(pid < 0){perror("fork failed\n");}if(pid == 0){ //Childclose(fd[0]);char * child = "I am a child";int j = 0;while(j < 5){write(fd[1], child, strlen(child) + 1);sleep(2);++j;}/*函数定义:ssize_t write (int fd, const void * buf, size_t count);函数说明:write()会把参数buf所指的内存写入count个字节到参数放到所指的文件内。返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。*/}else{close(fd[1]);char msg[100];int i = 0;while(i < 5){ssize_t s = read(fd[0], msg, 5);    //fd > 5, 父进程不会阻塞,while会执行多次,这个当然可以继续读啊,有的读干嘛不读。/*ssize_t s = read(fd[0], msg, 15),  fd < 5, 父进程会阻塞;当然要阻塞啊,阻塞等你子进程写东西过来嘛,多想想为什么。ssize_t read(int fd, void * buf, size_t count);read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。*/if (s>0){msg[s - 1] = '\0';}printf("%s\n", msg);i++;}}return 0;
}


这篇关于HomeWork ( 一) P46:Interlude: Process API的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/642048

相关文章

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

Go语言使用net/http构建一个RESTful API的示例代码

《Go语言使用net/http构建一个RESTfulAPI的示例代码》Go的标准库net/http提供了构建Web服务所需的强大功能,虽然众多第三方框架(如Gin、Echo)已经封装了很多功能,但... 目录引言一、什么是 RESTful API?二、实战目标:用户信息管理 API三、代码实现1. 用户数据

Python用Flask封装API及调用详解

《Python用Flask封装API及调用详解》本文介绍Flask的优势(轻量、灵活、易扩展),对比GET/POST表单/JSON请求方式,涵盖错误处理、开发建议及生产环境部署注意事项... 目录一、Flask的优势一、基础设置二、GET请求方式服务端代码客户端调用三、POST表单方式服务端代码客户端调用四

SpringBoot结合Knife4j进行API分组授权管理配置详解

《SpringBoot结合Knife4j进行API分组授权管理配置详解》在现代的微服务架构中,API文档和授权管理是不可或缺的一部分,本文将介绍如何在SpringBoot应用中集成Knife4j,并进... 目录环境准备配置 Swagger配置 Swagger OpenAPI自定义 Swagger UI 底

使用Python的requests库调用API接口的详细步骤

《使用Python的requests库调用API接口的详细步骤》使用Python的requests库调用API接口是开发中最常用的方式之一,它简化了HTTP请求的处理流程,以下是详细步骤和实战示例,涵... 目录一、准备工作:安装 requests 库二、基本调用流程(以 RESTful API 为例)1.

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

使用Python实现调用API获取图片存储到本地的方法

《使用Python实现调用API获取图片存储到本地的方法》开发一个自动化工具,用于从JSON数据源中提取图像ID,通过调用指定API获取未经压缩的原始图像文件,并确保下载结果与Postman等工具直接... 目录使用python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现