• 第5章 插叙:进程API


    Homework(Simulation):

            This simulation homework focuses on fork.py, a simple process creation simulator that shows how processes are related in a single “familial” tree. Read the relevant README for details about how to run the simulator.

    Questions:

    1. Run ./fork.py -s 10 and see which actions are taken. Can you predict what the process tree looks like at each step? Use the -c flag to check your answers. Try some different random seeds (-s) or add more actions (-a) to get the hang of it.

    python fork.py -s 10 -c

    python fork.py -s 10 -A a+b,b+c,c-,a+d -c

    2. One control the simulator gives you is the fork percentage, controlled by the -f flag. The higher it is, the more likely the next action is a fork; the lower it is, the more likely the action is an exit. Run the simulator with a large number of actions (e.g., -a 100) and vary the fork percentage from 0.1 to 0.9. What do you think the resulting final process trees will look like as the percentage changes? Check your answer with -c.

    python fork.py -s 10 -f 0.1 -a 10 -c

    python fork.py -s 10 -f 0.9 -a 10 -c

    3. Now, switch the output by using the -t flag (e.g., run ./fork.py -t). Given a set of process trees, can you tell which actions were taken?

    python3 fork.py -t -c

    4. One interesting thing to note is what happens when a child exits; what happens to its children in the process tree? To study this, let’s create a specific example: ./fork.py -A a+b,b+c,c+d,c+e,c-. This example has process ’a’ create ’b’, which in turn creates ’c’, which then creates ’d’ and ’e’. However, then, ’c’ exits. What do you think the process tree should like after the exit? What if you use the -R flag? Learn more about what happens to orphaned processes on your own to add more context.

    没有-R:d,e成为a的子进程

    python fork.py -A a+b,b+c,c+d,c+e,c- -c

    有-R:d,e成为b的子进程

    python fork.py -A a+b,b+c,c+d,c+e,c- -R -c

    5. One last flag to explore is the -F flag, which skips intermediate steps and only asks to fill in the final process tree. Run ./fork.py -F and see if you can write down the final tree by looking at the series of actions generated. Use different random seeds to try this a few times.

    python fork.py -F -c

    6. Finally, use both -t and -F together. This shows the final process tree, but then asks you to fill in the actions that took place. By looking at the tree, can you determine the exact actions that took place? In which cases can you tell? In which can’t you tell? Try some different random seeds to delve into this question

    python fork.py -t -F -c

    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 code, 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 something (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?

    说明父进程和子进程拥有相同但是独立的地址空间

    父进程和子进程对x所做的任何改变都是独立的

    1. #include
    2. #include
    3. int main(void)
    4. {
    5. int x = 1;
    6. printf("x is: %d\n", x);
    7. x = 100;
    8. int rc = fork();
    9. if (rc == 0)
    10. {
    11. printf("Hello, i am child (pid: %d)\n", getpid());
    12. printf("old x is %d\n", x);
    13. x++;
    14. printf("now x is %d\n", x);
    15. }
    16. else
    17. {
    18. printf("Hello, i am parent of %d (pid: %d)\n", rc, getpid());
    19. printf("old x is %d\n", x);
    20. x--;
    21. printf("now x is %d\n", x);
    22. }
    23. return 0;
    24. }

    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?

    子进程和父进程共享文件,父进程打开了文件a.txt而子进程继承了这个文件,因此也可以写入

    假设父进程先运行的话,子进程的写入不会覆盖父进程

    子进程先运行,父进程的写入同样也不会覆盖子进程

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main(void)
    7. {
    8. int fd = open("a.txt", O_RDWR, 2);
    9. int rc = fork();
    10. if (rc == 0)
    11. {
    12. printf("Hello! i am child (pid: %d)\n", getpid());
    13. char* str1 = "de";
    14. write(fd, str1, 2);
    15. }
    16. else
    17. {
    18. printf("Hello! i am parent of %d (pid: %d)\n", rc, getpid());
    19. char* str2 = "fgh";
    20. write(fd, str2, 3);
    21. }
    22. return 0;
    23. }

    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?

    vfork() :与 fork() 一样创建一个子进程,但保证子进程先运行,只有子进程调用 exec 或 exit 后,                 父进程才会被调用

    1. #include
    2. #include
    3. #include
    4. int main(void)
    5. {
    6. int rc = vfork();
    7. if (rc == 0)
    8. {
    9. printf("Hello! i am child (pid: %d)\n", getpid());
    10. exit(0);
    11. }
    12. else
    13. {
    14. printf("Goodbye! i am parent of %d (pid: %d)\n", rc, getpid());
    15. }
    16. return 0;
    17. }

    4. 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 (on Linux) execl(), execle(), execlp(), execv(), execvp(), and execvpe(). Why do you think there are so many variants of the same basic call?

    1. #include
    2. #include
    3. int main(void)
    4. {
    5. printf("hello world (pid:%d)\n",(int)getpid());
    6. int rc = fork();
    7. if(rc < 0)
    8. {
    9. fprintf(stderr,"fork failed\n");
    10. exit(1);
    11. }else if(rc == 0)
    12. {
    13. printf("hello, I am child (pid:%d)\n",(int)getpid());
    14. char *path = "/bin/ls";
    15. char* myargs[3] = {"ls","-l",NULL};
    16. char* env[] = {"PATH=/bin:/bin/usr",NULL};
    17. execl("/bin/ls","ls","-l",NULL);
    18. execv(path,myargs);
    19. execlp("ls","ls","-l",NULL);
    20. execvp(myargs[0],myargs);
    21. execle("/bin/ls","ls","-l",NULL,env);
    22. execvpe(myargs[0],myargs,env);
    23. printf("This shouldn't print out\n");
    24. }else
    25. {
    26. int rc_wait = wait(NULL);
    27. printf("hello, I am parent of %d (rc_wait:%d) (pid:%d)\n",
    28. rc,rc_wait,(int)getpid());
    29. }
    30. exit(0);
    31. }

    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?

    父进程调用wait()

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main(void)
    7. {
    8. int rc = fork();
    9. if (rc == 0)
    10. {
    11. printf("Hello! i am child (pid: %d)\n", getpid());
    12. }
    13. else
    14. {
    15. int wc = wait(NULL);
    16. printf("Hello! i am parent of %d (wc: %d) (pid: %d)\n", rc, wc, getpid());
    17. }
    18. return 0;
    19. }

     子进程调用wait(),wait()会返回-1,并且设置errno为ECHILD

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main(void)
    8. {
    9. int rc = fork();
    10. if (rc == 0)
    11. {
    12. int wc = wait(NULL);
    13. printf("Hello! i am child (wc: %d) (pid: %d)\n", wc, getpid());
    14. }
    15. else
    16. {
    17. printf("Hello! i am parent of %d (pid: %d)\n", rc, getpid());
    18. }
    19. if (errno == ECHILD)
    20. {
    21. printf("No child!\n");
    22. }
    23. return 0;
    24. }

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

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

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main(void)
    8. {
    9. int status;
    10. int rc = fork();
    11. int wc = waitpid(-1, &status, 0);
    12. if (rc == 0)
    13. {
    14. printf("Hello! i am child (wc: %d) (pid: %d)\n", wc, getpid());
    15. }
    16. else
    17. {
    18. printf("Hello! i am parent of %d (wc: %d) (pid: %d)\n", wc, rc, getpid());
    19. }
    20. if (errno == ECHILD)
    21. {
    22. printf("No child!\n");
    23. }
    24. return 0;
    25. }

    7. 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?

    在子进程中关闭标准输出,不会影响到父进程的输出

    1. #include
    2. #include
    3. #include
    4. int main(void)
    5. {
    6. int rc = vfork(); //让子进程先运行,看看对父进程有什么影响
    7. if (rc == 0)
    8. {
    9. printf("Hello! i am child (pid: %d)\n", getpid());
    10. close(STDOUT_FILENO);
    11. printf("What happend?\n");
    12. exit(0);
    13. }
    14. else
    15. {
    16. printf("Hello! i am parent of %d (pid: %d)\n", rc, getpid());
    17. }
    18. return 0;
    19. }

    8. 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. #include
    2. #include
    3. int main(void)
    4. {
    5. int p[2];
    6. int pid1;
    7. int pid2;
    8. pipe(p);
    9. pid1 = fork();
    10. if(pid1 == 0)
    11. {
    12. close(p[0]);
    13. write(p[1],"hello\n",6);
    14. exit(0);
    15. }
    16. pid2 = fork();
    17. int buf[10];
    18. if(pid2 == 0)
    19. {
    20. close(p[1]);
    21. read(p[0],buf,6);
    22. printf("%s",buf);
    23. exit(0);
    24. }
    25. wait(NULL);
    26. wait(NULL);
    27. exit(0);
    28. }
  • 相关阅读:
    《合成孔径雷达成像算法与实现》Figure5.3
    C++设计模式-原型(Prototype)
    企业级git工作流程
    SQL注入漏洞(postgresql注入)
    SQL——游标
    S7-1200PLC通过远程工具实现上传下载或修改PLC程序的具体方法
    Dockerfile解析
    竖式计算(c++基础)
    行内元素文字背景被截断的问题,如何进行修改?
    prometheus+nacos服务发现
  • 原文地址:https://blog.csdn.net/suitaox26456/article/details/127452226