【问题标题】:Check whether named pipe/FIFO is open for writing检查命名管道/FIFO 是否打开以进行写入
【发布时间】:2017-06-23 20:14:42
【问题描述】:

我已经为其他进程创建了一个命名管道来写入,并想检查其他进程是否正确启动,但不知道它的 PID。上下文是running a command in screen,确保命令正确启动。我希望这可能会奏效:

mkfifo /tmp/foo
echo hello > /tmp/foo &
lsof /tmp/foo

遗憾的是,lsof 没有报告 echoinotifywait 可能是另一种选择,但并不总是安装,我真的只想轮询一次,而不是阻止直到某个事件。

有什么方法可以检查命名管道是否可以写入?甚至一般开放?


更新:

一旦两端连接lsof 似乎工作。这实际上解决了我的问题,但是为了这个问题,我很想知道是否可以在没有阅读器的情况下检测到对命名管道的初始重定向。

> mkfifo /tmp/foo
> yes > /tmp/foo &
> lsof /tmp/foo
> cat /tmp/foo > /dev/null &
> lsof /tmp/foo
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF     NODE     NAME
yes     16915     user    1w  FIFO   8,18      0t0 16660270 /tmp/foo
cat     16950     user    3r  FIFO   8,18      0t0 16660270 /tmp/foo

【问题讨论】:

  • 当你说“open for writing”时,你的意思是有数据可以读取吗?对您来说,什么是不可写入的 FIFO?
  • 不是你要找的答案,但你可以写一个 .pid 文件
  • @Fred 如果您认为这个问题没有意义,也许“开放写作”是错误的术语。理想情况下,我希望列出重定向到该命名管道的进程。 IE。在mkfifo 之后,仅此而已,列表应该是空的。然后在yes > /tmp/foo 之后,我应该在列表中看到yes 的PID。
  • @我想澄清的是:您是在尝试确定编写器进程是否实际在写入,还是在尝试确定读者是否在实际阅读?
  • 我认为@teppic 是对的,您可能正在尝试解决错误的问题。不过,这是一个有趣的问题。

标签: bash named-pipes lsof


【解决方案1】:

更新 2:在使用 inotify-tools 之后,似乎没有办法获得命名管道已被打开以进行写入并被阻塞的通知。这可能就是为什么lsof 直到它有一个读取器和一个写入器才显示管道。

更新:在研究了命名管道之后,我认为没有任何方法可以单独使用命名管道。 推理:

  • 无法限制命名管道的写入者数量(不使用锁定)
  • 如果没有读取器,所有写入器都会阻塞
  • 如果有读取器,则没有写入器阻塞(大概只要内核缓冲区未满)

您可以尝试在短暂的超时时间内不向管道写入任何内容。如果超时,则写阻塞,表明有人已经打开管道进行写。

注意:正如 cmets 中所指出的,如果存在读取器并且可能足够快,我们的测试写入将不会阻塞,并且测试基本上会失败。注释掉下面的cat 行来测试一下。

#!/bin/bash

is_named_pipe_already_opened_for_writing() {
    local named_pipe="$1"
    # Make sure it's a named pipe
    if ! [ -p "$named_pipe" ]; then
        return 1
    fi
    # Try to write zero bytes in the background
    echo -n > "$named_pipe" &
    pid=$!
    # Wait a short amount of time
    sleep 0.1
    # Kill the background process. If kill succeeds, then
    # the write was blocked indicating that someone
    # else is already writing to the named pipe.
    kill $pid 2>/dev/null
}

PIPE=/tmp/foo

# Ignore any bash messages from killing below
trap : TERM

mkfifo $PIPE
# a writer
yes > $PIPE &
# a reader
cat $PIPE >/dev/null &

if is_named_pipe_already_opened_for_writing "$PIPE"; then
    echo "$PIPE is already being written to by another process"
else
    echo "$PIPE is NOT being written to by another process"
fi

jobs -pr | kill 2>/dev/null
rm -f $PIPE

【讨论】:

  • 是的,只要管道没有读取任何内容,就可以工作。
  • 依赖一个特定的睡眠持续时间(如果我理解正确的话,它应该为令状测试后台进程终止提供足够的时间)似乎有点脆弱。在某些情况下(例如高 CPU 或 IO 负载),这不会产生意外结果的风险吗?
  • 也许我做错了什么,因为我以为我记得这个工作。似乎echo 总是阻塞,除非有读者,即使是在全新的管道上。
  • @Fred:可能有问题,但在合理的情况下,可以选择合适的时间,既适用于测试又不会花费太长时间。
  • @jozxyqk:除非有读者,否则所有作者都会阻止。查看我对答案的更新。
【解决方案2】:

每个方向需要两个管道: 一个用于等待准备好新数据信号,另一个仅用于数据: 在我的情况下,逐行处理文件:

mkfifo r w;

cat file1 | while read l; do echo "$l" >w; read <r; done &
cat file2 | while read ln; do if read l <w; then echo "$ln"; echo "$l"; fi; echo 1>r;  done

【讨论】:

    猜你喜欢
    • 2012-07-31
    • 1970-01-01
    • 2012-01-23
    • 1970-01-01
    • 2016-05-24
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多