现在,我有一个蹩脚的检查来查看是否正在读取命名管道:
is_named_pipe_being_read() {
local named_pipe="$1"
echo "unlocked" > "$named_pipe" &
pid="$!"
# Wait a short amount of time
sleep 0.25
# Kill the background process. If kill succeeds, then
# the write was blocked
( kill -PIPE "$pid" ) &> /dev/null
}
如果终止有效(以 0 退出),则意味着没有人从管道中读取数据。
但我不想有 0.25 秒的延迟并启动不必要的进程,而是寻找一种方法来检查命名管道以查看它是否已打开以供读取?有什么方法可以确定是否有东西正在从中读取?
笔记:我无法在这次调用中从管道中读取数据,我只能写入它(因为使用命名管道,读取器的附加顺序似乎不受尊重 - 或者可能是最近获取数据的读取器,不是最老的读者)。
答案1
if /bin/echo unlocked 1<>fifo >fifo; then
there are readers
else
no there ain\'t
fi
is_named_pipe_being_read(){ /bin/echo unlocked 1<>"$1" >"$1"; }
如果没有读者,则会/bin/echo
被 a 杀死SIGPIPE
并返回非零状态。
您不能使用内置函数echo
(即使在子 shell 中),因为它将SIGPIPE
被捕获或杀死整个 shell。
就像OP的版本一样,这是破坏性的。如果您有 GNU dd,您可以尝试使用 打开文件O_NONBLOCK
,如下所示C
:
is_named_pipe_being_read(){ dd oflag=nonblock conv=notrunc,nocreat count=0 of="$1" 2>/dev/null; }
但这也好不了多少;如果管道中有其他写入者,则在命令退出时自动关闭 fifo 将导致所有读取者获得 EOF。
笔记:使用命名管道更多的是一种受虐狂或标准的迂腐行为[1]。由 unix 域套接字实现的 BSD 套接字 API 是无与伦比的好(这就是它统治世界的原因 ;-)),并且有一些程序(例如较新版本的程序)netcat
使其也可以从 shell 中使用。
[1] 在上面的例子中被击败或这事实上,根据标准,在 rw 模式下打开 fifo 是“未定义的”,尽管自 30 年前左右以来在大多数系统中都实现了相同的做法))。
答案2
我从这里偷了这个C程序https://stackoverflow.com/a/20694422/5047085:
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include <sys/stat.h>
#define SERVFIFO "/Users/alex/.locking/ql/locks/a/fifo.lock"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
void syserr(const char *str){
perror(str);
exit(1);
}
int main(int argc, char** argv){
umask(0);
// try to open for write with no readers
int fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);
if (fdw == -1){
syserr("non-blocking open for write with no readers failed");
}
// create a reader - the process itself - non-blocking
int fdr = open(SERVFIFO, O_RDONLY | O_NONBLOCK);
if (fdr == -1){
syserr("non-blocking open for read no writers failed");
}
// try again to open for write but this time with a reader
fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);
if (fdw == -1){
syserr("non-blocking open with readers failed");
}
printf("non-blocking open for write succeeded\n");
close(fdw);
close(fdr);
}
如果它以 0 退出,这意味着有人已经在从命名管道读取数据了?如果它以 1 退出,则意味着没有人正在读取它。
这可能是错误的,但基本测试表明它是有效的。 fifo 路径在上面的程序中是硬编码的。