文件IO详解(十一)---原子操作之文件共享

原子操作是指在一个进程中不允许被其他进程打断的操作就是原子操作。

=======================================================

在“文件共享”笔记中提到了单进程和多进程之间的文件共享,当同时对共享的文件进行写操作的时候,由于各自有独立的当前文件偏移量,所以很可能会出现数据覆盖的问题,正如该笔记中举的例子一样。为了解决数据覆盖的这个问题,就需要每次写之前将当前文件偏移量设置到文件末尾。为了实现这种设置,有两种方法:

  • 在写操作之前使用lseek函数将当前文件偏移量设置到文件末尾
  • 在open文件的时候加上 O_APPEND 标志。O_APPEND 标志的作用是可以每次写都会先将当前文件偏移量设置到文件末尾

======================================================

下面来详细说说这两种方法的区别:

第一种方法由于是先后调用两个系统调用lseek和write,属于非原子操作。而第二种方法虽然也相当于设置当前文件偏移量后再去写操作,但是属于原子操作。

在单进程中由于操作的顺序都是确定的,所以两种方法都是可以的,没有任何影响。但是在多进程中只能使用第二种方法,第一种方法不能使用。原因如下:

在多进程中,由于各个进程是并发执行的,任何一个进程可能在任何一个时刻被打断(除了原子操作期间)。假设使用的是第一种方法,进程A在调用lseek函数设置当前文件偏移量后,便被进程B打断,进程B开始调用lseek函数设置当前文件偏移量,然后调用write函数往里面写数据,此时文件长度已经增加了;之后进程A被恢复执行,调用write函数向其中写数据,由于此时进程A的当前文件偏移量仍然是之前的文件末尾,所以进程A向其中写入的数据会覆盖了进程B之前写入的数据。所以第一种方法解决不了数据覆盖的问题。

而如果采用第二种方法,进程A在调用write函数向其中写入数据时,由于设置了 O_APPEND标志,所以会先设置当前文件偏移量到文件末尾,由于此操作是原子操作,故不可能会被其他进程打断,一定会先写完数据后才可能被打断,故不可能出现上面采用第一种方法的情况,可以完美解决数据覆盖的问题。

时间: 2024-08-10 02:09:22

文件IO详解(十一)---原子操作之文件共享的相关文章

文件IO详解(十)---文件共享(多进程之间、单进程之间)

在同一个进程中,实现文件共享的方法有两种: 多次使用open函数打开相同文件 使用dup/dup2函数或者fcntl函数 ======================================================== 对于第一种方法: 每次使用open函数打开文件时,操作系统内核中都会创建一个不同的文件表项(struct file结构体),但是这些不同的struct file结构体最终都会指向同一个struct inode结构体,因为一个文件只能对应唯一的一个struct in

文件IO详解(五)---open函数详解

open函数用来在进程中打开文件,如果成功则返回一个文件描述符fd. ======================================================= 函数原型: 函数参数: pathname:打开文件的路径名 flags:用来控制打开文件的模式 mode:用来设置创建文件的权限(rwx).当flags中带有O_CREAT时才有效. 返回值: 调用成功时返回一个文件描述符fd 调用失败时返回-1,并修改errno ==========================

文件IO详解(七)---lseek函数详解

lseek函数用来设置当前文件偏移量. ====================================================== 函数原型: 函数参数: fd:要操作的文件描述符 offset:基于whence参数的偏移量 whence:参考点位置 返回值: 调用成功时返回当前相对于文件开头的偏移量,以字节为单位 调用失败时返回 -1,并修改errno的值 ======================================================= when

文件IO详解(十四)---dup函数和dup2函数详解

dup和dup2函数是在进程中用来复制文件描述符的,可以实现文件共享. ======================================================== 函数原型: 函数参数: oldfd:要被复制的文件描述符 newfd:在dup2函数中指定的新文件描述符 返回值: 调用成功返回新的文件描述符 调用失败返回 -1 ======================================================== 使用dup或者dup2函数实现文件共

文件IO详解(三)---Linux虚拟文件系统

http://blog.chinaunix.net/uid-14735472-id-2921377.html 讲解虚拟文件系统的一些数据结构以及之间的关系,有些地方看不懂 http://www.docin.com/p-941544538.html 讲解了进程打开文件时内核所建立的各种数据结构之间的联系 在给磁盘分区后,每个分区中都可以建立起各自独立的文件系统,建立的物理文件系统可以是相同的,也可以是不同的.那么不同的物理文件系统的组织数据的方式肯定是不同的,比如说ext2文件系统组织数据的方式是

文件IO详解(十二)---原子操作之创建文件

使用open打开文件时,使用 O_CREAT 标志的话,就会在不存在文件的情况下去创建文件.所以说实际应该是有两个操作,一个是判断文件是否存在,另一个就是创建文件:而且这两个操作是作为一个原子操作执行的.如果不是作为一个原子操作执行的,那么就会分解成如下的程序段: 如果不作为一个原子操作执行那么在多进程中可能会出问题,假设两个操作不是作为原子操作执行的,当进程A在判断文件不存在后,便被挂起,进程B得以执行,然后创建了文件且向其中写入了数据,然后进程A被恢复,接着执行creat函数试图创建文件,而

文件IO详解(四)---标准输入、标准输出和标准错误

每个进程都会默认打开3个文件描述符,即0.1.2.其中0代表标准输入流.1代表标准输出流.2代表标准错误流.通常标准输入流对应着键盘的设备文件.标准输出流和错误流对应着显示器的设备文件.在编程中通常使用宏STDIN_FILENO.STDOUT_FILENO和STDERR_FILENO分别来代表0,1,2. 要注意一点: 0.1.2这三个文件描述符对应的是标准输入流.标准输出流和标准错误流而不是键盘设备文件和显示器设备文件.只是默认标准输入流对应着键盘设备文件,标准输出和错误对应着显示器设备文件.

(待续)文件IO详解(十六)---fcntl函数详解

fcntl函数是用来在进程中实现对文件的多种操作的函数,通过不同的命令可以实现不同的操作.常用的操作有复制文件描述符.为文件设置建议锁和获取设置文件控制标志等. ======================================================= 函数原型: ======================================================= 操作一:复制文件描述符实现文件共享 函数参数: fd:要操作的文件描述符 cmd:F_DUPFD ar

文件IO详解(十三)---pread函数和pwrite函数详解

pread和pwrite函数是Linux提供的另外一种读取和写入文件的操作.pread函数的操作可以看作是顺序调用了lseek函数和read函数,同样pwrite函数也类似. ====================================================== 函数原型: 函数参数: fd:要操作的文件描述符 buf:在pread函数中表示存储读出数据的内存首地址,在pwrite函数中表示写入数据的内存首地址 count:在pread函数中表示希望读出的字节数,在pwri