<UNIX环境高级编程>文件共享及fork函数
UNIX系统支持在不同进程间共享打开文件。内核使用3种数据结构表示打开文件,它们之间的关系决定了文件共享方面一个进程对另一个进程可能产生的影响。
内核维持了3个表,即进程表,文件表和v节点表。具体如下:
1>每个进程在进程表中都有一个纪录项,记录项中包含一张打开文件描述符表,每个描述符占用一项。与每个文件描述符相关联的是:
a. 文件描述符标志(close_on_exec);
b. 指向一个文件表项的指针。
2>内核为所有打开文件维持一张文件表。每个文件表项包含:
a. 文件状态标志(读、写、添写、同步和非阻塞等);
b. 当前文件偏移量;
c. 指向该文件v节点表项的指针。
3>每个打开文件(或设备)都有一个v节点(v-node)结构。v节点包含了文件类型和对此文件进行各种操作函数的指针。对于大多数文件,v节点还包含了该文件的i节点(i-node,索引节点),这些信息是在打开文件是从磁盘上读入内存用的。i节点包含了文件的所有者、文件长度、指向文件实际数据块在磁盘上所在位置的指针。(UNIX文件系统中有更多关于i节点的介绍。另,Linux没有使用v节点,而是采用了一个与文件系统相关的i节点和一个与文件系统无关的i节点)

图1 打开文件的内核数据结构
上图显示了一个进程对应的3张表之间的关系。该进程有两个不同打开文件:一个文件从标准输入打开(文件描述符0),另一个文件从标准输出打开(文件描述符1)。

图2 两个独立进程各自打开同一个文件
一个现有的进程可以调用fork函数创建一个新进程。由fork进程创建的进程称为子进程,frok函数调用一次,返回两次。子进程的返回值是0,父进程的返回是子进程的进程ID。子进程和父进程继续执行fork调用之后的指令。(两个都会执行,但是执行先顺序不定,这取决于内核所使用的调度算法。) 子进程是父进程的副本,如子进程获得父进程数据空间、堆和栈的副本。父进程与子进程并不共享存储空间,但共享正文段。但许多实现并不执行父进程数据的完全副本,而是使用写时复制(Copy-On-Write, COW)技术。
下列代码中可以看到子进程对变量所做的改变并不影响父进程中该变量的值。
#include "apue.h"
;
char buf[] = "a write to stdout\n";
int
main(void)
{
int var;
pid_t pid;
;
) != )
err_sys("write error");
printf("before fork\n");
) {
err_sys("fork error");
} ) {
glob++;
var++;
} else {
sleep();
}
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit();
}
如果执行该程序,则可得到:

可以看到,第一次为直接执行,输出到标准输出;而第二次重定向到文件了。导致两次执行同样的代码,得到的结果却不同。我们知道,文件I/O函数是不带缓冲的,标准I/O库是带缓冲的。而标准输出连接到终端设备,则它是行缓冲的;否则它是全缓冲的。第一次执行中,printf函数输出到标准输出,缓冲区由换行符冲洗。而重定向到文件时,缓冲区是全缓冲的,在fork调用之前调用了printf一次。但当调用fork时,该行数据仍在缓冲区中,然后再将父进程数据空间复制到子进程中时,该缓冲区数据也被复制到子进程中,此时父进程和子进程各自有个带该行的缓冲区。在exit之前的第二个printf将其数据追加到已有的缓冲区中。当进程终止时,其缓冲区中的内容都被写到相应文件中。
对上述程序,需要注意的一点是:在重定向父进程的标准输出时,子进程的标准输出也被重定向。fork的一个特性是父进程所有打开文件描述符都复制到子进程中。父进程和子进程每个相同的打开描述符共享一个文件表项。重要的一点是,父进程和子进程共享同一个文件偏移量。

转载请注明地址<http://www.cnblogs.com/qiuyi116/p/4322466.html>,谢谢!
参考《UNIX环境编程》第三版
<UNIX环境高级编程>文件共享及fork函数的更多相关文章
- UNIX环境高级编程——sigqueue、sigsuspend函数
一.sigqueue函数 功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用. int sigqueue(pid_t pid, int sig, ...
- UNIX环境高级编程——线程和fork
当线程调用fork时,就为子进程创建了整个进程地址空间的副本.子进程通过继承整个地址空间的副本,也从父进程那里继承了所有互斥量.读写锁和条件变量的状态.如果父进程包含多个线程,子进程在fork返回以后 ...
- 《UNIX环境高级编程》笔记--sigaction函数
sigaction函数的功能是检查或修改指定信号相关联的处理动作,此函数取代UNIX早期版本使用的signal函数. #include<signal.h> int sigaction(in ...
- 《UNIX环境高级编程》笔记--read函数,write函数,lseek函数
1.read函数 调用read函数从文件去读数据,函数定义如下: #include <unistd.h> ssize_t read(int filedes, void* buff, siz ...
- UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数
UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数 gethostname() getppername() getsockname() gethostbyname() ...
- 《UNIX环境高级编程(第3版)》
<UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...
- multiple definition of `err_sys' 《UNIX环境高级编程》
本文地址:http://www.cnblogs.com/yhLinux/p/4079930.html 问题描述: [点击此处直接看解决方案] 在练习<UNIX环境高级编程>APUE程序清单 ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
随机推荐
- utf8乱码解决方案[适合tomcat部署的jsp应用]
转:http://blog.csdn.net/cn_gaowei/article/details/6673539 1. java类: CharacterEncodingFilter im ...
- 使用Knoctout.分页
要点:点击标签翻页部分时,pageValue自动加1. 1.api中的方法 public ArticleListModel Get(int page,string _class) { var list ...
- 今天写一些 有关iOS 多图片组合 成一张图片的问题。保持原像素不变
1.要求:服务器给一张图片模板,要在模版上镂空,然后添加一些别的图片,然后组合成一张图,这个模版的像素 不是固定的,有可能比 当前手机屏幕大.所以,在组合截图的时候,有一定的要求. 贴代码: /** ...
- 日志文件C++ 时间 文件 行数
#include <stdio.h> #include<windows.h> #include <time.h> #define Line __LINE__ #de ...
- [AngularJS] Accessible Button Events
Often buttons need to be handled by JavaScript, and if done improperly it can lead to accessibility ...
- 一个.Net程序员:既然选择了编程,只管风雨兼程(转)
一个.Net程序员:既然选择了编程,只管风雨兼程 一次会议记录是不会有人感兴趣的,做标题党也是不道德的.所以,走了个折衷的路线,标题不叫会议记录, 内容不纯总结,技术加吐槽,经验加总结. 对于一个程序 ...
- BugZilla的安装过程简明教程
Bugzilla+Mysql+iis+perl模块+ ActivePerl 安装过程 (原:http://www.cnblogs.com/Warmsunshine/archive/2012/03/25 ...
- Oracle 通过sql profile为sql语句加hint
sql profile最大的优点是在不修改sql语句和会话执行环境的情况下去优化sql的执行效率,适合无法在应用程序中修改sql时.sql profile最常用方法大概是:--创建产生sql tuni ...
- Unix 网络编程(2)——TCP API
TCP C/S套接口函数一般调用过程及基本函数 如上图所示的TCP连接的基本过程.一般来说,服务器先于客户端运行,服务器程序运行的基本过程是: socket()函数创建服务器段socket. bind ...
- Android 自学之列表选择框Spinner
列表选择框(Spinner)与Swing编程里面的Spinner不同,这里的Spinner其实就是一个列表选项框. Spinner是ViewGroup的间接子类,因此他也可作为容器使用. Spinne ...