open中O_EXCL选项的介绍与分析

open的man中的介绍:

O_EXCL
              Ensure  that  this  call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open() will fail.  The behavior of O_EXCL is undefined if O_CREAT is not specified.
 
              When these two flags are specified, symbolic links are not followed: if pathname is a symbolic link, then open() fails regardless of where the symbolic link points to.
 
              O_EXCL is only supported on NFS when using NFSv3 or later on kernel 2.6 or later.  In environments where NFS O_EXCL support is not provided, programs that rely on it for performing locking tasks will contain a race  condition.   Portable  programs  that want  to  perform  atomic  file  locking  using a lockfile, and need to avoid reliance on NFS support for O_EXCL, can create a unique file on the same file system (e.g., incorporating hostname and PID), and use link(2) to make a link  to  the  lockfile.
              If  link(2)  returns  0,  the  lock  is  successful.  Otherwise, use stat(2) on the unique file to check if its link count has increased to 2, in which case the lock is also successful.
 

一般 O_CREAT 和 O_EXCL 会组合出现。

如果使用O_CREAT时,文件存在,就返回错误信息(open返回-1,errno是17 'EEXIST 17'),它可以测试文件是否存在。它是原子操作的,为什么这么说呢,见下例子(来自某论坛):

设想这样一个需求:某个任务要求只能单个进程执行,不能多个进程同时执行。
但是不能确保多个进程同时启动,尝试执行这个任务。
这样就进一步要求,只有第一个执行的进程可以继续,后续尝试执行的进程都报错退出。
 
方案之一就是使用带有O_EXCL标志的open()尝试打开一个文件。
第一个进程执行时文件并不存在,它能成功创建文件并继续执行。
第二个及后续的其它进程会因为文件已存在,从而open()失败,进程退出。
 
如果不使用O_EXCL标志,那你的代码可能要这样写:
if( access(file, R_OK) == -1 )
  open(file, O_RDWR | O_CREAT,0666);
...
 
这个逻辑是有潜在的问题的,那就是判断文件是否存在与创建文件是两个独立的系统调用。
如果进程1执行access,判断出文件并不存在;
然后由于操作系统的调度策略,进程1暂停执行,进程2执行,进程2也会判断出文件不存在。
 
最终结果就是:两个进程调用open时都会成功,然后继续执行。这样就有多个进程同时执行这个任务了。
 
 
现在体会到“O_CREAT | O_EXCL”的作用了吧。
 

 

你可能感兴趣的:(open中O_EXCL选项的介绍与分析)