O_EXCL

来源:互联网 发布:淘宝买东西分期付款 编辑:程序博客网 时间:2024/06/01 19:50

open系统调用:

#include <fcntl.h>int open(const char *pathname, int oflag, ... /*mode_t mode */ );其中,oflag有个可选值为:

O_EXCL

Generate an error if O_CREAT is also specified and the file already exists. 

This test for whether the file already exists and the creation of the file if it doesn't exist is an atomic operation. 

We describe atomic operations in more detail in Section 3.11.

译文:当 O_CREAT 与 O_EXCL 同时使用,并且如果要打开的文件已经存在,那么该调用就返回error,表明打开不成功。因此,我们可以使用该方法(即 O_CREAT 与 O_EXCL 同时使用)来实现以下三步的原子性操作:1 检查某个文件是否存在2 如果文件不存在,就创建该文件,返回 success3 如果文件已经存在,就返回error,通知调用者文件已经存在---------------------------------------------华丽丽的分割线-----------------------------------以下是从网上找的一些信息:$ man open
......
  O_EXCL Ensure that this call creates the file: if this flag is specified in conjunc-
  tion with O_CREAT, and pathname already exists, then open() will fail. The
behavior of O_EXCL is undefined if O_CREAT is not specified.=============================================================================================设想这样一个需求:某个任务要求只能单个进程执行,不能多个进程同时执行。
但是不能确保多个进程同时启动,尝试执行这个任务。
这样就进一步要求,只有第一个执行的进程可以继续,后续尝试执行的进程都报错退出。

方案之一就是使用带有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_EXCL|O_CREAT)与 O_CREAT 的区别:1 单独使用 O_CREAT 时,无论文件在该调用执行时,是否存在,都会成功返回(不考虑所在目录权限、文件权限的问题)。如果应用程序只要求确保文件在后续程序执行时,该文件已经存在,则单独使用 O_CREAT 就可满足该应用要求。但有一个不足之处就是:当open成功返回后,我们需要知道该文件是之前已经存在呢,还是之前不存在而刚刚创建出来的。如果有这种需求,那么 单独使用 O_CREAT 就不能搞定了。此时,就需要使用(O_EXCL|O_CREAT)。2 当使用(O_EXCL|O_CREAT)时,若文件已存在,则返回错误;过不存在,则返回成功。但返回不论成功、错误,返回后,文件肯定已经存在了。因此,该方式能够给程序员提供更多的信息量。

区别应该就在这里吧。

那么在apue中,在介绍 Ensure that only one copy of a daemon is running中,作者并没有使用(O_EXCL|O_CREAT)来通过判断某个文件是否存在来判断是否有某个进程的其它实例正在运行。而是采用了O_CREAT,而后加“写锁”的方式。

想想这两种方式的特点:

如果采用 (O_EXCL|O_CREAT)来实现单实例进程,那么进程结束之前,必须要先删除锁文件,否则,以后该程序就无法运行了。因此问题就在如何保证删除锁文件。比如突然断电,程序还没来得及删除锁文件,那么下次再无法运行了。处理好这个问题需要额外画一些功夫。

apue中采用的采用 record lock 的方式,应该是不存在上面提到的这种问题。

原创粉丝点击