同一进程共享操作相同的文件

在同一个进程中多次open打开同一文件时,文件描述符可能会相同吗?

答:不可能。在同一进程里面,一旦某个文件描述符被用了,在close释放之前,别人不可能使用,所以指向同一文件的描述符不可能相同。

代码演示

 #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #define FILE_NAME "./file.txt" void print_error(char * str)
{
perror(str);
exit(-);
} int main(void)
{
int fd1 = ;
int fd2 = ; fd1 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(- == fd1) print_error("1 open fail"); fd2 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(fd2 == -) print_error("2 open fail"); printf("fd1 = %d, fd2 = %d\n", fd1, fd2); while()
{
write(fd2, "world\n", );
sleep();
write(fd1, "hello\n", );
} return ;
}

file.txt文件内容会出现覆盖写情况,看看共享操作时的文件描述符表长啥样

由图知道,正是由于不同的文件描述符,各自对应一个独立的文件表,在文件表中有属于自己的“文件位移量”,开始时都是0。各自从0开始写,每写一个字节向后移动一个字节,他们写的位置是重叠的,因此肯定会相互的覆盖。

问题如何解决

指定O_APPEND即可解决。必须每个open都要指定,有一个不指定就会覆盖,就先过马路一样,都要准守交通规则才能安全,开车的和行人,只要有一个不准守都会出事。

为什么使用O_APPEND可以解决?

文件长度信息是大家共享的,当文件被写入数据后,文件长度就会被更新,都指定O_APPEND后,使用不同的文件描述符写数据时,都会使用文件长度更新自己的文件位移量,保证每次都是在文件的最末尾写数据,就不会出现相互覆盖的情况。

多个进程之间,共享操作相同文件

代码演示

shareOp_file1.c

 #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #define FILE_NAME "./file.txt" void print_error(char * str)
{
perror(str);
exit(-);
} int main(void)
{
int fd1 = ; fd1 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(- == fd1) print_error("1 open fail"); printf("fd1 = %d\n", fd1); while()
{
write(fd1, "hello\n", );
sleep();
} return ;
}

shareOp_file2.c

 #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #define FILE_NAME "./file.txt" void print_error(char * str)
{
perror(str);
exit(-);
} int main(void)
{
int fd1 = ; fd1 = open(FILE_NAME, O_RDWR|O_TRUNC|O_APPEND);
if(- == fd1) print_error("1 open fail"); printf("fd1 = %d\n", fd1); while()
{
write(fd1, "world\n", );
sleep();
} return ;
}

不同进程打开同一文件时,各自使用的文件描述符值可能相等,比如我们例子中的1和2进程,它们open后的描述符就相等。之所以相同,是因为不同的进程有自己独立的文件描述符池,都是0~1023的范围,各自分配自己的,有可能分派到相等值的文件描述符。

进程表 和 文件描述符表

覆盖的原因

和单个进程打开多个文件类似,这种情况也会覆盖写。其原因是因为因为各自有独立的文件位移量。

解决办法

同样的,指定O_APPEND标志,写操作时,使用文件长度去更新文件位移量,保证各自操作时,都在文件的尾部操作,就不会出现相互覆盖的情况。

父子进程共享操作文件

独立打开文件

这种情况即多个进程独立打开同一文件实现共享操作,只不过这里面进程之间是父子关系

代码演示

 #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int main(void)
{
pid_t ret = ;
int fd = ; ret = fork();
if(ret > )
{
fd = open("./file.txt", O_RDWR|O_CREAT|O_APPEND, ); write(fd, "hello\n", );
}
else if(ret == )
{
fd = open("./file.txt", O_RDWR|O_CREAT|O_APPEND, ); write(fd, "world\n", );
} return ;
}

文件表结构

独立打开同一文件时,父子进程各自的文件描述符,指向的是不同的文件表。因为拥有不同的文件表,所以他们拥有各自独立的文件读写位置,会出现相互覆盖情况,如果不想相互覆盖,需要加O_APPEND标志。

fork之前打开文件

代码演示

 #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int main(void)
{
pid_t ret = ;
int fd = ; fd = open("./file.txt", O_RDWR|O_CREAT, );
ret = fork();
if(ret > )
{
write(fd, "hello\n", );
printf("p, uid = %d, gid = %d\n", getuid(), getgid());
}
else if(ret == )
{
write(fd, "world\n", );
printf("c, uid = %d, gid = %d\n", getuid(), getgid());
} return ;
}

文件表结构

子进程会继承父进程已经打开的文件描述符,如果父进程的3描述符指向了某个文件,子进程所继承的文件描述符3也会指向这个文件。像这种继承的情况,父子进程这两个相同的“文件描述符”指向的是相同的“文件表”。由于共享的是相同的文件表,所以拥有共同的文件读写位置,不会出现覆盖的情况。

子进程的0 1 2这三个打开的文件描述符,其实也是从父进程那里继承过来的,并不是子进程自己去打开的,同样的父进程的0 1 2又是从它的父进程那里继承过来的,最根溯源的话,都是从最原始的进程哪里继承过来的,参考:进程控制——三大主要进程 ,最原始的进程是init进程。

init进程会去打开标准输入,标注输出、标准出错输出这三个文件,然后0 1 2分别指向打开的文件,之后所有进程的0 1 2,实际上都是从最开始的init进程那里继承而来的。

初级文件IO——若干种文件共享操作 如何影响 文件文件描述符表的更多相关文章

  1. 文件的三种打开方式及with管理文件上下文

    文件的三种打开方式及with管理文件上下文 一.文件的三种打开方式 1.1 只读 f = open(r'D:\pycharm\yjy\上海python学习\456.txt','r',encoding= ...

  2. LInux文件基础知识和文件目录操作(二)文件I/O操作

    1.文件I/O操作分为两部分来讲解: 第一部分是非缓冲文件操作,这种操作适合于比较小规模文件的读写和对实时性要求很高的设备的数据通信,这类操作是系统调用提供的: 第二部分是缓冲文件操作,所面向的则是大 ...

  3. java读取txt文件,对字符串进行操作后导出txt文件

    嘿嘿,代码略为简单,不再多做解释,直接上码! package org.lq.com.util; import java.io.File; import java.io.InputStreamReade ...

  4. Lua的文件IO操作

    Lua 标准库 - 输入输出处理(input and output facilities) 转载于:http://blog.csdn.net/duanxuyun 文本Tag: Lua [IT168 技 ...

  5. 【UNIX环境高级编程】文件 IO 操作 一 ( open | close | creat | lseek | write | read )

    博客地址 : http://blog.csdn.net/shulianghan/article/details/46980271 一. 文件打开关闭操作相关函数介绍 1. open 函数 (1) op ...

  6. 《嵌入式linux应用程序开发标准教程》笔记——6.文件IO编程

    前段时间看APUE,确实比较详细,不过过于详细了,当成工具书倒是比较合适,还是读一读这种培训机构的书籍,进度会比较快,遇到问题时再回去翻翻APUE,这样的效率可能更高一些. <嵌入式linux应 ...

  7. 三、文件IO——系统调用

    3.1 文件描述符 文件IO 系统调用是不带缓存的,文件 I/O 系统调用不是 ANSI C 的组成部分,是 POSIX 的组成部分. 系统调用与C库: C库函数的IO 的底层还是调用系统调用 I/O ...

  8. 文件IO和标准IO的区别【转】

    一.先来了解下什么是文件I/O和标准I/O: 文件I/O:文件I/O称之为不带缓存的IO(unbuffered I/O).不带缓存指的是每个read,write都调用内核中的一个系统调用.也就是一般所 ...

  9. 标准IO与文件IO 的区别【转】

    本文转载自:http://blog.sina.com.cn/s/blog_63f31f3401013jrn.html 先来了解下什么是标准IO以及文件IO. 标准IO:标准I/O是ANSI C建立的一 ...

随机推荐

  1. iOS-reveal 的使用

    Reveal是一个iOS程序界面调试工具.使用Reveal,我们可以在iOS开发时动态地查看和修改应用程序的界面. 对于动态或复杂的交互界面,手写UI是不可避免的.通过Reveal,我们可以方便地调试 ...

  2. 让IIS支持解析.json格式文件

    原文出处链接及本声明. 原文链接:https://blog.csdn.net/jumtre/article/details/72630730 1.IIS内点击网站进入网站主页设置界面: 2.双击MIM ...

  3. 用例建模 Use Case Modeling

    用例建模 以您的工程实践项目为例,在理解项目需求的基础上进行用例建模,抽取Abstract use case,画出用例图,并确定每一个用例的范围High level use case,对关键用例进一步 ...

  4. Path环境变量的作用

    作用: 当我们要求系统运行一个程序(例如a.exe)而没有告诉它程序所在的完整路径时,系统会先在当前目录寻找是否存在a.exe,如果找到,直接运行:如果没有找到,会去path路径下面找.设置path, ...

  5. SQL注入(字符型)

       靶场:sqli-labs @SQLi最重要的一点:别上来就对着输入框注入,完整语句写出来,始终在语句中写完整的,最后把完整的一部分截取出来作为输入 @URL编码:为避免歧义,URL中,如 %2b ...

  6. TensorFlow.训练_资料(有视频)

    ZC:自己训练 的文章 貌似 能度娘出来很多,得 自己弄过才知道哪些个是坑 哪些个好用...(在CSDN文章的右侧 也有列出很多相关的文章链接)(貌似 度娘的关键字是"TensorFlow ...

  7. 解决SpringMVC拦截静态资源的问题

    优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往 ...

  8. flink两种安装方式

    Flink Standalone 集群 HA 配置 1. HA 集群环境规划 使用三台节点实现两主两从集群(由于笔记本性能限制,不能开启太多虚拟机,其实使用三 台和四台机器在安装配置上没有本质区别) ...

  9. 什么是云解析DNS?

    产品概述 云解析DNS(Alibaba Cloud DNS)是一种安全.快速.稳定.可扩展的权威DNS服务,云解析DNS为企业和开发者将易于管理识别的域名转换为计算机用于互连通信的数字IP地址,从而将 ...

  10. ARM-常见考题和知识点

    1. ARMv7 7中状态,ARMv8对应的状态 2. TEE知识 3. ARM寄存器及作用 4. ARM内部总线AHB APB 5. 1. Thumb | Arm指令区别 编写Thumb指令时,先要 ...