本文主要是介绍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
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?
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?
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?
Write a program that calls fork() and then calls some form of exec() to run the program /bin/ls. See 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?
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?
Write a slight modification of the previous program, this time using waitpid() instead of wait(). When would waitpid() be useful?
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?
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;
}
输出为: 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;
}
输出为: 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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!