对fork函数理解
2015-07-29 11:05
267 查看
头文件: #include <unistd.h>
1. 创建一个子进程,失败返回-1。
2. 调用一次,返回两次。分别在父子进程中返回子进程的PID和0。利用返回值的不同,可以分别为父子进程编写不同的处理分支。
3. 子进程是父进程的副本,子进程获得父进程数据段和堆栈段(包括I/O流缓冲区)的拷贝,但子进程共享父进程的代码段。
4. 函数调用后父子进程各自继续运行,其先后顺序不确定。某些实现可以保证子进程先被调度。
5. 函数调用后, 父进程的文件描述符表(进程级)也会被复制到子进程中,二者共享同一个文件表(内核级)。
6. 总进程数或实际用户ID所拥有的进程数, 超过系统限制,该函数将失败。
7. 一个进程如果希望创建自己的副本并执行同一份代码,或希望与另一个程序并发地运行,都可以使用该函数。
注意:fork之前的代码只有父进程执行,fork之后的代码父子进程都有机会执行, 受代码逻辑的控制而进入不同分支。
pid_t fork (void);
1. 创建一个子进程,失败返回-1。
2. 调用一次,返回两次。分别在父子进程中返回子进程的PID和0。利用返回值的不同,可以分别为父子进程编写不同的处理分支。
#include <stdio.h> #include <unistd.h> int main (void) { printf ("%u进程:我要调用fork()了...\n", getpid ()); pid_t pid = fork (); if (pid == -1) { perror ("fork"); return -1; } if (pid == 0) { printf ("%u进程:我是%u进程的子进程。\n", getpid (), getppid ()); return 0; } printf ("%u进程:我是%u进程的父进程。\n", getpid (), pid); sleep (1); return 0; }
3. 子进程是父进程的副本,子进程获得父进程数据段和堆栈段(包括I/O流缓冲区)的拷贝,但子进程共享父进程的代码段。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int global = 100; int main (void) { int local = 200; char* heap = (char*)malloc (256 * sizeof (char)); sprintf (heap, "ABC"); printf ("父进程:%d %d %s\n", global, local, heap); pid_t pid = fork (); if (pid == -1) { perror ("fork"); return -1; } if (pid == 0) { global++; local++; sprintf (heap, "XYZ"); printf ("子进程:%d %d %s\n", global, local, heap); free (heap); return 0; } sleep (1); printf ("父进程:%d %d %s\n", global, local, heap); free (heap); return 0; }
#include <stdio.h> #include <unistd.h> int main (void) { printf ("ABC"); pid_t pid = fork (); if (pid == -1) { perror ("fork"); return -1; } if (pid == 0) { printf ("XYZ\n"); return 0; } sleep (1); printf ("\n"); return 0; }第一行输出ABCXYZ,第二行输出ABC
4. 函数调用后父子进程各自继续运行,其先后顺序不确定。某些实现可以保证子进程先被调度。
#include <stdio.h> #include <unistd.h> int main (void) { printf ("父进程:"); int a, b, c; scanf ("%d%d%d", &a, &b, &c); pid_t pid = fork (); if (pid == -1) { perror ("fork"); return -1; } if (pid == 0) { scanf ("%d%d%d", &a, &b, &c); printf ("子进程:%d %d %d\n", a, b, c); return 0; } sleep (1); printf ("父进程:%d %d %d\n", a, b, c); return 0; }
5. 函数调用后, 父进程的文件描述符表(进程级)也会被复制到子进程中,二者共享同一个文件表(内核级)。
#include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> int main (void) { int fd = open ("ftab.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); if (fd == -1) { perror ("open"); return -1; } const char* text = "Hello, World !"; if (write (fd, text, strlen (text) * sizeof (text[0])) == -1) { perror ("write"); return -1; } pid_t pid = fork (); if (pid == -1) { perror ("fork"); return -1; } if (pid == 0) { if (lseek (fd, -7, SEEK_CUR) == -1) { perror ("lseek"); return -1; } close (fd); return 0; } sleep (1); text = "Linux"; if (write (fd, text, strlen (text) * sizeof (text[0])) == -1) { perror ("write"); return -1; } close (fd); return 0; }结果:Hello ,Linux !
6. 总进程数或实际用户ID所拥有的进程数, 超过系统限制,该函数将失败。
7. 一个进程如果希望创建自己的副本并执行同一份代码,或希望与另一个程序并发地运行,都可以使用该函数。
注意:fork之前的代码只有父进程执行,fork之后的代码父子进程都有机会执行, 受代码逻辑的控制而进入不同分支。
相关文章推荐
- 【Java】取当前.class文件的编译位置
- MVVM
- DateUtil
- 消息机制和RPC的区别
- vim 操作技巧
- php使用gzip压缩传输js和css文件的方法
- 手机短信验证码的实现
- Android官方命令深入分析之bmgr
- Rational Team Concert 2
- 与Linux关机、重启相关的几个命令
- hdoj 4539 郑厂长系列故事——排兵布阵 【状压DP入门】
- Zend Framework1-Zend_Controller_Request请求对象的封装
- Android官方命令深入分析之bmgr
- 使用MJExtension中要注意的地方
- JavaScript中的cacheStorage使用详解
- redis+keepalived高可用
- subprocess shell=True的测试
- Android的异步任务AsyncTask详解
- Oracle触发器实现自动编号
- php5.5-win64位下curl扩展不能开启解决方法