Прямо сейчас у меня есть эта паршивая проверка, чтобы увидеть, считывается ли именованный канал:
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
}
если kill срабатывает (выходит с 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
завершен с помощью SIGPIPE
и вернет ненулевой статус, если читателей нет.
Вы не можете использовать встроенную функцию echo
(даже в подоболочке), поскольку она SIGPIPE
будет либо перехвачена, либо уничтожит всю оболочку.
Как и версия из 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]. API сокетов BSD, реализованное в сокетах домена unix, несравнимо лучше (вот почему оно правит миром ;-)), и есть программы, подобные более новым версиям, которые netcat
делают его в некотором роде пригодным для использования из оболочки.
[1] который терпит поражение в примерах, подобных приведенным выше илиэтоттем фактом, что открытие 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 жестко закодирован в программе выше.