进程原语一. fork函数
1. 函数原型
pid_t fork(void);
子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。
2. 以具体的程序讲解fork函数特点
第一段代码
1. #include <stdio.h> 2. #include <sys/types.h> 3. #include <unistd.h> 4. 5. int main(void) 6. { 7. //fork创建一个新进程 8. pid_t p1 = -1; 9. 10. //fork之前的操作只有父父进程才有 11. p1 = fork(); //调用一次fork函数会返回两次 12. 13. if(p1 == 0) 14. { 15. //这里一定是子进程 16. //先sleep一下,让父进程先死 17. sleep(1); 18. 19. printf("子进程, pid = %d.\n", getpid()); 20. printf("子进程, p1 = %d.\n", p1); 21. printf("子进程中父进程的ID = %d.\n", getppid()); 22. } 23. if(p1 > 0) 24. { 25. //这里一定是父进程 26. printf("父进程, pid = %d.\n", getpid()); 27. printf("父进程, p1 = %d.\n", p1); 28. } 29. 30. if(p1 < 0) 31. { 32. 33. //这里一定是出错了 34. } 35. 36. //在这里的操作,父子进程都有 37. //printf("hello world, pid = %d.\n", getpid()); 38. 39. return 0; 40. }
输出结果如下:
结论:
1. 结论: 2. 3. (1)fork函数调用一次会返回两次,返回值等于0的就是子进程,返回值大于0的就是父进程 4. 5. (2)fork的返回值在子进程中等于0, 在父进程中返回值等于本次fork创建的子进程的PID 6. 7. (3)这里在子进程中打印父进程PID,为什么跟在父进程中打印父进程的PID结果不一样? 8. 9. 是因为在执行的时候,父进程先执行完,然后子进程就没有父进程了;这是在子进程中打印的父进程PID就是init进程
第二段代码
1. #include <stdio.h> 2. #include <unistd.h> 3. #include <stdlib.h> 4. #include <sys/types.h> 5. 6. int main(void) 7. { 8. pid_t pid ; 9. //调用一次返回2次,在父进程返回子进程的PID,在子进程中返回0 10. 11. int n = 10; 12. pid = fork(); 13. 14. if(pid > 0) 15. {/*in parent*/ 16. while(1) 17. { 18. printf("I am parent %d\n", n++); 19. printf("my pid = %d.\n", getpid()); 20. printf("my parent pid = %d.\n", getppid()); 21. sleep(1); 22. } 23. } 24. 25. else if(pid == 0) 26. {/*in child*/ 27. while(1) 28. { 29. printf("I am child %d\n", n++); 30. printf("my pid = %d.\n", getpid()); 31. printf("my parent pid = %d.\n", getppid()); 32. sleep(3); 33. 34. } 35. } 36. 37. else 38. { 39. perror("fork"); 40. exit(0); 41. } 42. 43. return 0; 44. }
结论:
1. (1)父子进程中n值分别独立加,说明子进程从父进程中克隆过来的数据,已经不是共享的了。两者有自己独立的空间。 2. 3. (2)0-3G放应用层代码,子进程直接从父进程中拷贝,3-4G是内核空间 4. 5. (3)读时共享,写时复制(copy on write)(好处:节省物理内存开销,省去直接复制的时间)
fork函数创建子进程之后,如果只是用返回值去区分父子进程,这样的方式效率太低,下面会介绍更好的方法!!!