【问题标题】:atomically removing the first line of a file AND returning it原子地删除文件的第一行并返回它
【发布时间】:2016-10-16 03:18:55
【问题描述】:

我想使用纯文本文件作为我的应用程序的任务队列(用于写入数据库,尽管这无关紧要),其中:

  1. 我通过echo "some task" >> task_queue.txt将一个项目添加到队列中
  2. 我以原子方式从队列中删除一个项目

对于 2。如果我在多个线程或进程中访问/修改 task_queue.txt,我不知道如何避免竞争条件。以下不是原子的:

ITEM=`head -1 task_queue.txt`
sed -i '1d' task_queue.txt
# process the item in the application

Bash 是否提供了比使用锁定文件更优雅的方式来做到这一点?我以前从未使用过flock,所以我不知道这是否很混乱(例如,当我的应用程序的任务处理失败时)。

【问题讨论】:

    标签: bash file locking atomic


    【解决方案1】:

    所有这些都受到竞争条件的影响,在检查文件是否被访问和对文件执行操作之间。虽然大概检查和操作之间的时间会很短。


    一种方法是使用pgrep-f 选项来匹配完整的命令行,并匹配文件是否匹配,即是否有任何进程访问该文件。这假设进程没有修改它的命令行。

    可以这样做:

    if ! pgrep -f task_queue.txt &>/dev/null; then
        ## File not Open, do stuff
    else
        ## File is Open, do stuff
    fi
    

    另一种方法包括解析lsoffuser(这与解析/proc/PID/fd/* 相同):

    if ! lsof /path/to/task_queue.txt &>/dev/null; then
        ## File not Open, do stuff
    else
        ## File is Open, do stuff
    fi
    

    类似fuser:

    if ! fuser /path/to/task_queue.txt &>/dev/null; then
        ## File not Open, do stuff
    else
        ## File is Open, do stuff
    fi
    

    请注意,这里我们将lsof/fuser 的 STDOUT 和 STDERR 都发送到 /dev/null,这可能并不总是可取的,因为可能会有一些警告/错误,因为我们只依赖于退出状态,所有这些都将被视为文件正在使用中。如果lsof/fuser 对不同的事件有不同的退出状态,这将更容易实现,但我只能看到1 用于每种失败或不匹配。

    【讨论】:

    • 有趣的方法,我不知道pgrep -f。我想知道这是否比使用羊群更好。我想我必须同时追求这两种选择,看看我对哪一种更有信心。
    • 嗯,实际上if 正文中的“东西”不可能一直保留文件描述符吗? 2个命令之间可能有一小段时间文件没有打开,这可能会允许另一个进程窃取它。
    • @Sridhar-Sarnobat 显然pgrep 和文件操作之间可能存在竞争条件,无论多么小。如果你想要精确,你应该看看锁定机制,例如flock.
    • 是的,我猜。虽然在pgrep 之后不是我最关心的问题。更大的问题是我后面的多个命令。但我很欣赏这些建议和代码示例。
    • @Sridhar-Sarnobat 然后您可以(可能)使用while 构造,并一次运行一个命令(如果可能)。
    【解决方案2】:

    虽然我无法确认它是原子的,但它比我自己(可能)编写的任何东西都要原子,并且对于我的非任务关键型应用程序来说已经足够了:

    sed -i -e '1 w /dev/stdout' -e '1d' task_queue.txt
    

    (学分:https://unix.stackexchange.com/a/108479/7000

    【讨论】:

      猜你喜欢
      • 2014-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-21
      • 2017-02-25
      • 1970-01-01
      相关资源
      最近更新 更多