(APUE点滴记录) 进程控制之fork与vfork
来源:互联网 发布:刘琨 祖逖 知乎 编辑:程序博客网 时间:2024/06/03 17:04
2013-03-02 wcdj
1 fork —— “生个新娃”
#include <unistd.h>#include <stdio.h>#include <stdlib.h>int glob = 6;// external variable in initialized datachar buf[] = "a write to stdout\n";intmain(int argc, char** argv){int var;// automatic variable on the stackpid_t pid;var = 88;if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)printf("write error\n");printf("before fork\n");// we do not flush stdoutif ((pid = fork()) < 0){printf("fork error\n");}else if (pid == 0)// child{printf("child's parent pid:%d\n", getppid());glob++;var++;}else{sleep(3);// parent}printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);exit(0);}/*output:mba:APUE gerryyang$ gcc -o fork fork.c mba:APUE gerryyang$ ./fork a write to stdoutbefore forkchild's parent pid:574pid = 575, glob = 7, var = 89pid = 574, glob = 6, var = 88mba:APUE gerryyang$ ./fork > tmp.outmba:APUE gerryyang$ cat tmp.out a write to stdoutbefore forkchild's parent pid:617pid = 618, glob = 7, var = 89before forkpid = 617, glob = 6, var = 88 */在UNIX环境下,一个现有进程可以使用fork函数创建一个新的进程(子进程child process)。
#include <unstd.h>
pid_t fork();
需要注意:
(1) 返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1。
(2) fork函数被调用一次,但返回两次。两次返回的唯一区别是:子进程的返回值是0,而父进程的返回值是新子进程的进程ID。
(3) 进程ID 0 总是由内核交换进程使用,所以一个子进程的进程ID不可能为0。
(4) 子进程可以调用getppid以获得其父进程的进程ID。
(5) 子进程和父进程继续执行fork调用之后的指令。
(6) 子进程是父进程的“副本”。例如,子进程获得父进程数据空间、堆和栈的“副本”。注意,父、子进程并不共享这些存储空间部分。父、子进程共享正文段。
注意:由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、堆和栈的完全复制,而使用“写时复制(Copy-On-Write, COW)”技术,这些区域由父、子进程共享,而且内核将它们的访问权限改变为只读的,如果父、子进程中任何一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储器系统中的一“页”。
(7) 一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的,这取决于内核所使用的调度算法。如果要求父、子进程之间相互同步,则要求某种形式的IPC。
(8) 缓冲区的复制。write函数是不带缓冲的,但是标准I/O库是带缓冲的。当以交互方式运行时,只得到该printf输出的行一次,其原因是标准输出缓冲区由换行符冲洗;但是当将标准输出重定向到一个文件时,却得到printf输出行两次,其原因是,在fork之前调用了printf一次,但当调用fork时,该行数据仍在缓冲区中,然后在将父进程数据空间复制到子进程中时,该缓冲区也被复制到子进程中。于是那时父、子进程各自有了带该行内容的标准I/O缓冲区。在exit之前的第二个printf将其数据添加到现有的缓冲区中,当每个进程终止时,最终会冲洗其缓冲区中的副本。
(9) 文件共享。在重定向父进程的标准输出时,子进程的标准输出也被重定向。实际上,fork的一个特性是:父进程的所有打开文件描述符都被复制到子进程中。父、子进程的每个相同的打开描述符共享一个文件表项。这种共享文件的方式使父、子进程对同一文件使用了一个文件偏移量。
注意:如果父、子进程写到同一个描述符文件,但又没有任何形式的同步,那么它们的输出就会混乱。
在fork之后处理文件描述符有两种常见的情况:
【1】父进程等待子进程完成。
在这种情况下,父进程无需对其描述符做任何处理,当子进程终止后,它曾进行过读、写操作的任一共享描述符的文件偏移量已执行了相应更新。
【2】父、子进程各自执行不同的程序段。(常用)
在这种情况下,在fork之后,父、子进程各自关闭它们不需要使用的文件描述符,这样就不会干扰对方使用的文件描述符。这种方法是网络服务进程中经常使用的。
(10) 除了打开文件之外,父进程的很多其他属性也由子进程继承。
(11) fork失败的两个主要原因是:
【1】系统中已经有了太多的进程。
【2】该实际用户ID的进程总数超过了系统限制。CHILD_MAX规定了每个实际用户ID在任一时刻可具有的最大进程数。
(11) fork的两种用法:
【1】一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中常见的,父进程等待客户端的服务请求,当这种请求到达时,父进程调用fork,使子进程处理此请求,父进程则继续等待下一个服务请求到达。
【2】一个进程要执行一个不同的程序。这对shell是常见的情况,在这种情况下,子进程从fork返回后立即调用exec。
2 vfork——“子母同体,用于spawn”
#include <unistd.h>#include <stdio.h>#include <stdlib.h>int glob = 6;// external variable in initialized dataintmain(int argc, char** argv){int var;// automatic variable on the stackpid_t pid;var = 88;printf("before fork\n");// we do not flush stdoutif ((pid = vfork()) < 0)// use vfork{printf("fork error\n");}else if (pid == 0)// child{printf("child's parent pid:%d\n", getppid());// sleep a well for doing somethingsleep(3);printf("child done\n");glob++;var++;_exit(0);// child terminates}// parent continues hereprintf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);exit(0);}/* output:mba:APUE gerryyang$ gcc -o vfork vfork.cmba:APUE gerryyang$ ./vfork before forkchild's parent pid:1030child donepid = 1030, glob = 7, var = 89*/vfork函数的调用序列和返回值与fork相同,但两者的语义不同。
#include <unistd.h>
pid_t vfork();
vfork -- spawn new process in a virtual memory efficient way
DESCRIPTION
Vfork() can be used to create new processes without fully copying the address space
of the old process, which is horrendously inefficient in a paged environment. It is
useful when the purpose of fork(2) would have been to create a new system context for
an execve. Vfork() differs from fork in that the child borrows the parent's memory
and thread of control until a call to execve(2) or an exit (either by a call to
exit(2) or abnormally.) The parent process is suspended while the child is using its
resources.
需要注意:
(1) vfork用于创建一个新进程,而该新进程的目的是exec一个新程序。
(2) vfork与fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就不会访问此地址空间。在子进程调用exec或exit之前,它在父进程的空间中运行,这种优化工作方式在某些UNIX的页式虚拟存储器实现中提高了效率。不复制比COW的部分复制要更快一些。
(3) vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。
注意:如果在调用这两个函数之前,子进程依赖于父进程的进一步动作,则会导致死锁。
(4) 代码片段中,子进程对变量glob和var进行了改变,结果也改变了父进程中的变量值。因为子进程在父进程的地址空间中运行。
(5) _exit和exit的区别。_exit不执行标准I/O缓冲的冲洗操作。大多数exit的现代实现不再在流的关闭方面自找麻烦,因为进程即将终止,那时内核将关闭在进程中已打开的所有文件描述符,在库中关闭它们,只是增加了开销而不会带来任何益处。
- (APUE点滴记录) 进程控制之fork与vfork
- APUE--fork与vfork
- Linux学习之进程fork()与vfork()
- Unix进程控制之1---fork和vfork函数
- 多进程 fork()与vfork()
- 进程控制-进程创建(fork、vfork)
- Linux的进程学习笔记之fork与vfork
- 进程控制1--fork vfork函数
- 进程控制1--fork vfork函数
- Linux控制进程实战fork /vfork
- APUE之fork两次与僵尸进程的问题
- linux进程 fork与vfork简解
- linux 进程创建clone、fork与vfork
- Linux进程创建fork()与vfork()
- linux 进程创建clone、fork与vfork
- 进程创建函数fork与vfork
- fork与vfork创建进程的区别
- Linux多进程中的fork与vfork
- 孙鑫19课笔记
- 笔记本电脑参数简析(学生选择)
- OpenStack Nova存储管理聪明做法
- 求最短路径算法之Floyd算法
- 【原创】商论之:幼儿园的思维和学前班的做法!
- (APUE点滴记录) 进程控制之fork与vfork
- UVa10405 - Longest Common Subsequence ( 最长公共子序列 )
- 名企招聘经典面试编程题集锦[第21-30题]
- 我的大学十年——林锐
- linux下discuz 论坛安装
- 消息映射和命令传递
- 题目1:排序
- sizeof() && 数组名和指针
- 工厂模式