Проверьте, открыт ли именованный канал для чтения.

Проверьте, открыт ли именованный канал для чтения.

Прямо сейчас у меня есть эта паршивая проверка, чтобы увидеть, считывается ли именованный канал:

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 жестко закодирован в программе выше.

Связанный контент