1. 场景概述
  在多线程开发中,互斥锁可以用于对临界资源的保护,防止数据的不一致,这是为普遍的使用方法。那在多进程中如何处理文件之间的同步呢?我们看看下面的图:

  图中所示的是两个进程在无同步的情况下同时更新同一个文件的过程,其主要的操作是:
  1. 从文件中读取序号。
  2. 使用这个序号完成应用程序定义的任务。
  3. 递增这个序号并将其写回文件中。
  从图中可得知两个进程读取分别增加了所读取到的序号,并写回到了文件中,但是如果有相互互斥的话,后的值应该是1002,而不是所示的1001。为了防止出现这种情况,Linux提供了flock(对整个文件加锁)、fcntl(对整个文件区域加锁)两个函数来做进程间的文件同步。同时也可以使用信号量来完成所需的同步,但通常使用文件锁会更好一些,因为内核能够自动将锁与文件关联起来。
  2. flock()
  flock的声明如下
  #include <sys/file.h>
  // Returns 0 on success, or -1 on error
  int flock (intfd, int operation);
  fcntl()函数提供了比该函数更为强大的功能,并且所拥有的功能也覆盖了flock()所拥有的功能,但是在某些应用中任然使用着flock()函数,并且在继承和锁释放方面的一些语义 中flock()与fcntl()还是有所不同的。
  flock()系统调用是在整个文件中加锁,通过对传入的fd所指向的文件进行操作,然后在通过operation参数所设置的值来确定做什么样的操作。operation可以赋如下值:

  在默认情况下,如果另一个进程已经持有了文件上的一个不兼容的锁,那么flock()会阻塞。如果需要防止这种情况的出现,可以在operation参数中对这些值取OR(|)。在这种情况下,如果一个进程已经持有了文件上的一个不兼容锁,那么flock()会阻塞,相反,它会返回-1,并将errno设置成EWOULDBLOCK。
  任意数量的进程可同时持有一个文件上的共享锁,但子任意时刻只能有一个进程能够持有一个文件上的互斥锁,(这有点类似读写锁)。下图是进程A先设置了锁,进程B后设置锁的支持情况:

  无论程序以什么模式打开了文件(读、写或者读写),该文件上都可以放置一把共享锁或互斥锁。在实际操作过程中,参数operation可以指定对应的值将共享锁转换成互斥锁(反之亦然)。将一个共享锁转换成互斥锁,如果另一个进程要获取该文件的共享锁则会阻塞,除非operation参数指定了LOCK_NB标记,即:(LOCK_SH | LOCK_NB)。锁的转换过程不是一个原子操作,在转换的过程中首先会删除既有的锁,然后创建新锁。