首页 > 代码库 > 文件IO详解(十一)---原子操作之文件共享

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

原子操作是指在一个进程中不允许被其他进程打断的操作就是原子操作。
=======================================================
    在“文件共享”笔记中提到了单进程和多进程之间的文件共享,当同时对共享的文件进行写操作的时候,由于各自有独立的当前文件偏移量,所以很可能会出现数据覆盖的问题,正如该笔记中举的例子一样。为了解决数据覆盖的这个问题,就需要每次写之前将当前文件偏移量设置到文件末尾。为了实现这种设置,有两种方法:
  • 在写操作之前使用lseek函数将当前文件偏移量设置到文件末尾
  • 在open文件的时候加上 O_APPEND 标志。O_APPEND 标志的作用是可以每次写都会先将当前文件偏移量设置到文件末尾
======================================================
下面来详细说说这两种方法的区别:
    第一种方法由于是先后调用两个系统调用lseek和write,属于非原子操作。而第二种方法虽然也相当于设置当前文件偏移量后再去写操作,但是属于原子操作。
    在单进程中由于操作的顺序都是确定的,所以两种方法都是可以的,没有任何影响。但是在多进程中只能使用第二种方法,第一种方法不能使用。原因如下:
    在多进程中,由于各个进程是并发执行的,任何一个进程可能在任何一个时刻被打断(除了原子操作期间)。假设使用的是第一种方法,进程A在调用lseek函数设置当前文件偏移量后,便被进程B打断,进程B开始调用lseek函数设置当前文件偏移量,然后调用write函数往里面写数据,此时文件长度已经增加了;之后进程A被恢复执行,调用write函数向其中写数据,由于此时进程A的当前文件偏移量仍然是之前的文件末尾,所以进程A向其中写入的数据会覆盖了进程B之前写入的数据。所以第一种方法解决不了数据覆盖的问题。
    而如果采用第二种方法,进程A在调用write函数向其中写入数据时,由于设置了 O_APPEND标志,所以会先设置当前文件偏移量到文件末尾,由于此操作是原子操作,故不可能会被其他进程打断,一定会先写完数据后才可能被打断,故不可能出现上面采用第一种方法的情况,可以完美解决数据覆盖的问题。
 

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