如何在Linux中自动创建锁定文件?

时间:2013-06-27 20:34:19

标签: linux file-io flock fcntl

场景:我有很多进程需要通过网络获取文件。如果文件已经下载,我希望它缓存在磁盘上。如果另一个进程正在下载该文件,则阻止它直到完成下载。

我一直在努力寻找最简单的方法。显而易见的方法是:

create file w/ an exclusive lock active on it only if it doesn't exist (O_CREAT | O_EXCL)
if file exists already:
   open file and acquire exclusive lock
else:
   download to newly created file
release lock

该系统通过(看似)没有竞争条件来实现上述目标

不幸的是,我找不到有关如何使用open()等创建一个在Linux中锁定的文件的文档。如果我将创建步骤拆分为:

open w/ O_CREAT | O_EXCL
flock

创建和锁定之间现在存在竞争条件(非创建进程在创建者之前获取锁定)。

我意识到我可以在每个文件中使用一个外部锁定文件(例如filename +'.lock),这是我在尝试创建文件名之前获得的,但这感觉...不优雅(我现在需要担心如何文件实际上有.lock后缀!)

无论如何以原子方式创建并锁定它(如Windows提供的那样),还是外部锁定文件方法几乎是标准/必需的?

3 个答案:

答案 0 :(得分:7)

无论如何都存在种族。如果文件可能存在,也可能不存在,那么在尝试锁定之前必须先测试它的存在。但是如果文件是你的互斥锁,那么你就不可能这样做,“如果文件已存在”(假)和“下载到新创建的文件”之间的空间是不受约束的。另一个过程可以通过创建文件并在下载开始之前开始下载,你会破坏它。

基本上不要在这里使用fcntl锁,使用文件本身的存在。如果文件已经存在,那么带有O_CREAT和O_EXCL的open()将会失败,并告诉您其他人先到达那里。

答案 1 :(得分:0)

为什么不使用lockfile实用程序?

  

实施例

     

假设您要确保访问该文件" important"是   序列化,即不应超过一个程序或shell脚本   允许访问它。为简单起见,我们假设它是   一个shell脚本。在这种情况下,您可以这样解决:

...
lockfile important.lock
...
access_"important"_to_your_hearts_content
...
rm -f important.lock
...

答案 2 :(得分:0)

我现在正在努力解决类似的问题,这就是 带我到你的问题。如我所见,本质是:

int fd = open(path, O_CREAT|O_RDWR|O_EXCL, mode);
if (fd == -1)
    {
    /* File already exists. */
    the_file_already_exists(fd);
    }
else
    {
    /* I just now created the file.  Now I'll lock it. */

    /* But first I'll deliberately create a race condition!! */
    deliberately_fork_another_process_that_handles_file(path);

    int code = flock(fd,LOCK_EX);
    if (code < 0)
        {
        perror("flock");
        exit(1);
        }

    /* I now have the exclusive lock.  I can write to the file at will --
    or CAN I??  See below. */
    write_to_the_file_at_will(fd);
    }

显然,在现实生活中,我永远不会故意创造这种比赛条件, 但它的等效功能肯定会在真实系统中偶然发生。那 其他过程,例如,打开文件进行读取,获取共享 锁定它,然后读取文件。它将看到一个空文件。那可能意味着 正在进行写操作,但这可能意味着文件正在 只是空的,那是正确的最终答案。

如果不允许使用空文件,则阅读器可以完全按照正确的方式运行 如果文件丢失,它将表现出来。毕竟,如果读者已经开始 一毫秒之前,它无论如何都无法打开文件。在这 打开文件后,读者需要检查文件是否为空。

如果允许使用空文件,那么您有点困惑,我没有 对此的现成答案。

我的问题是,第一次创建文件时,我想写一些 一种默认值,因为我想“自动初始化”一个新值 系统,而不必预先创建它可能需要的每个可能的文件。那 处理文件的其他过程可能已经本身对其进行了初始化! 据我所知,与此同时,其他三个流程可能也已运行, 改变了价值。在那种情况下,我当然不想“写入文件 在获得排他锁之后,“随意”,因为我将破坏所有这些 变化。

我想答案就是上面的代码,以确保文件是 在写之前先清空。如果它不是空的,那么代码应该表现出来 就像文件已经存在一样:即应调用:

the_file_already_exists(fd);

也许所有讨论的底线是每个过程 以任何方式处理文件应检查文件是否为空并表现 相应地。再说一次,如果允许空文件,那我还不能想 任何有保证的解决方案。如果有一些,这些都没有必要 创建文件并将其锁定为单个原子序列的方法,但是我没有 认为有任何方法可以做到这一点。