<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 环境高级编 ...
随机推荐
- 从零开始学android开发-项目debug
在红框处能看到变量值
- 关于Excel Networkdays方法的实现
最近一个程序要求excel输出的日期差为Networkdays. 在网上找了下,没有找到很好的具体实现方法. 要说明的是,微软的Microsoft.Office.Interop.Excel已经实现的N ...
- Redis的Time Event与File Event的微妙关系
redis里设计了两类事件,一类是file event,一类是time event. 其中file event主要为网络事件而设计,而time event为一些后台事件设计. 在两类事件的管理设计上, ...
- Windows二进制文件的Python扩展包
http://www.lfd.uci.edu/~gohlke/pythonlibs/ https://pypi.python.org/simple/
- careercup-C和C++ 13.5
13.5 谈谈C语言关键字”volatile”的意义(或重要性)? 解答 关键字volatile的作用是指示编译器,即使代码不对变量做任何改动,该变量的值仍可能被外界修改.操作系统.硬件或其他线程都可 ...
- Jordan Lecture Note-2: Maximal Margin Classifier
Maximal Margin Classifier Logistic Regression 与 SVM 思路的不同点:logistic regression强调所有点尽可能远离中间的那条分割线,而SV ...
- Android Studio编译FBReaderJ
我的个人环境 系统:mac (windows应该差不多) 工具:android studio 2.1.2 注意:一定要安装NDK!一定要安装NDK!一定要安装NDK! 如何安装NDK ...
- RadioGroup&RadioButton
RadioGroup提供多选一机制:属性orientation:“vertlcal” or “horizontal” @Override public void onCheckedChanged(Ra ...
- [转]ODBC连接ORACLE数据库的设置
本文转自:http://www.cppblog.com/edog/articles/1420.html 首先安装Oracle,以Oracle 817为例,作为ODBC开发者的客户端,才能使用Oracl ...
- 【linux操作命令】mysql
1.linux下启动mysql的命令: mysqladmin start /ect/init.d/mysql start (前面为mysql的安装路径) 2.linux下重启mysql的命令: mys ...