【问题标题】:fcntl, lockf, which is better to use for file locking?fcntl,lockf,哪个更好用于文件锁定?
【发布时间】:2010-10-09 04:29:41
【问题描述】:

寻找有关 fcntllockf 的优点缺点的信息 用于文件锁定。例如,哪个更适合便携性?我目前正在编写一个 linux 守护进程,想知道哪个更适合用于强制互斥。

【问题讨论】:

    标签: c linux file locking


    【解决方案1】:

    lockf和fcntl有什么区别:

    在许多系统上,lockf() 库例程只是 fcntl() 的包装。也就是说lockf 提供了fcntl 所提供的功能的一个子集。

    Source

    但在某些系统上,fcntllockf 锁是完全独立的。

    Source

    由于它依赖于实现,请确保始终使用相同的约定。因此,要么始终从您的两个进程中使用 lockf,要么始终使用 fcntl。它们很有可能可以互换,但使用同一个更安全。

    你选择哪一个并不重要。


    关于强制与建议锁定的一些说明:

    unix/linux 中的锁定默认是advisory,这意味着其他进程不需要遵循设置的锁定规则。因此,您锁定哪种方式并不重要,只要您的合作流程也使用相同的约定即可。

    Linux 确实支持强制锁定,但前提是您的文件系统安装时使用了选项 on 并设置了文件特殊属性。可以使用mount -o mand挂载文件系统并设置文件属性g-x,g+s启用强制锁,然后使用fcntllockf。有关强制锁如何工作的更多信息,请参阅here

    请注意,锁不是应用于单个文件,而是应用于 inode。这意味着指向相同文件数据的 2 个文件名将共享相同的锁定状态。

    另一方面,在 Windows 中,您可以主动以独占方式打开文件,这将阻止其他进程完全打开它。即使他们愿意。即,锁是强制性的。 Windows 和文件锁也是如此。任何具有适当访问权限的打开文件句柄的进程都可以锁定文件的一部分,并且没有其他进程能够访问该部分。


    强制锁在 Linux 中的工作原理:

    关于强制锁,如果一个进程用读锁锁定文件的一个区域,那么其他进程可以读取但不能写入该区域。如果一个进程用写锁锁定了文件的一个区域,那么其他进程就不能读取或写入该文件。当不允许进程访问文件的一部分时会发生什么取决于您是否指定了O_NONBLOCK。如果设置了阻塞,它将等待执行操作。如果没有设置阻塞,你会得到一个错误代码EAGAIN


    NFS 警告:

    如果您在 NFS 挂载上使用锁定命令,请务必小心。该行为是未定义的,并且无论是仅使用本地锁定还是支持远程锁定,实现都存在很大差异。

    【讨论】:

    • 这不再正确。文件锁定确实适用于 nfs 3.0,但仅适用于 fcntl,而不适用于群
    • “但在某些系统上,fcntl 和 lockf 锁是完全独立的”——不。在某些系统上,fcntl 和lockf 锁是完全独立的,如您链接到的文章中所述。但是,fcntl 和 lockf 锁总是相关的(只是与flock 无关)。
    【解决方案2】:

    这两个接口都是 POSIX 标准的一部分,现在这两个接口在大多数系统上都可用(我刚刚检查了 Linux、FreeBSD、Mac OS X 和 Solaris)。因此,请选择更符合您要求的并使用它。

    请注意:当一个进程使用 fcntl 锁定一个文件而另一个使用 lockf 锁定文件时会发生什么情况尚未明确。在大多数系统中,这些是等效的操作(实际上在 Linux 下 lockf 是在 fcntl 之上实现的),但 POSIX 表示它们的交互是未指定的。因此,如果您正在与使用这两个接口之一的另一个进程进行互操作,请选择同一个。

    其他人写道,锁定只是建议性的:您负责检查一个区域是否被锁定。另外,如果您想使用锁定功能,请不要使用 stdio 功能。

    【讨论】:

      【解决方案3】:

      在这种情况下(即“编写 Linux 守护程序并想知道哪个更适合强制互斥”),您的主要关注点应该是:

      1. 锁定的文件是本地文件还是可以在 NFS 上?
        • 例如用户能否欺骗您在 NFS 上创建和锁定您的守护进程的 pid 文件?
      2. forking 或当守护进程以极端偏见终止时,锁将如何表现,例如kill -9?

      flockfcntl 命令在这两种情况下的行为不同。

      我的建议是使用fcntl。您可以参考File locking article on Wikipedia,深入讨论这两种解决方案所涉及的问题:

      flock 和 fcntl 都有各自的特点 偶尔会困扰程序员 其他操作系统。是否植绒 锁在网络文件系统上工作, 比如NFS,是实现 依赖。在 BSD 系统上调用群发 是成功的无操作。在 Linux 之前 到 2.6.12 对 NFS 文件的群调用 只会在当地采取行动。内核 2.6.12 及以上在 NFS 上实现群调用 使用 POSIX 字节范围锁的文件。 这些锁将对其他人可见 实现的 NFS 客户端 fcntl()/POSIX locks.1锁升级 和降级释放旧锁 在应用新锁之前。如果 应用程序降级独家 锁定到一个共享锁,而另一个 应用程序被阻止等待 排他锁,后一种应用 将获得排他锁和 第一个应用程序将被锁定。 与文件关联的所有 fcntl 锁 对于给定的进程,当 该文件的任何文件描述符是 被那个进程关闭,即使是锁 从未请求该文件 描述符。此外,fcntl 锁不是 由子进程继承。这 fcntl 关闭语义特别 麻烦的应用程序 调用可能的子程序库 访问文件。

      【讨论】:

        【解决方案4】:

        我最近在使用 fcntl 和flock 时遇到了一个问题,我觉得我应该在这里报告,因为搜索任一术语都会显示此页面在两者的顶部附近。

        请注意,如上所述,BSD 锁是建议性。对于那些不知道 OSX (darwin) 是 BSD 的人。打开要写入的文件时必须记住这一点。

        要使用 fcntl/flock,您必须首先打开文件并获取其 ID。但是,如果您使用“w”打开文件,该文件将立即清零。如果您的进程由于文件在其他地方使用而未能获得锁定,它很可能会返回,将文件保留为 0kb。拥有锁的进程现在会发现文件已经从它下面消失了,通常会带来灾难性的结果。

        为了纠正这种情况,当使用文件锁定时,永远不要打开文件“w”,而是打开它“a”,以追加。然后,如果成功获取了锁,您就可以像“w”那样安全地清除文件,即。 :

        fseek(fileHandle, 0, SEEK_SET);//移到开头

        ftruncate(fileno((FILE *) fileHandle), 0);//清除

        这对我来说是一个不愉快的教训。

        【讨论】:

        • 我想你的意思是用"r+" (O_RDWR) 而不是"a" (O_APPEND) 打开文件——显然没有O_TRUNC 就像"w" 一样
        【解决方案5】:

        由于您只是编写一个使用它进行互斥的守护程序,因此它们是等效的,毕竟您的应用程序只需要与自身兼容。

        文件锁定机制的诀窍是保持一致 - 使用一个并坚持下去。改变它们是个坏主意。

        我在这里假设文件系统将是本地文件系统 - 如果不是,那么所有的赌注都没有了,NFS / 其他网络文件系统以不同程度的有效性处理锁定(在某些情况下没有)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-14
          • 2019-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-06
          • 1970-01-01
          • 2021-06-21
          相关资源
          最近更新 更多