@Kosterio, при работе с FIFO надо понимать, что этот файл задуман как точка рандеву, поэтому при open()
обычно процессы блокируются, ожидая один другого.
Для процесса читателя открывать FIFO с O_RDWR
действительно разумно (не будет блокировки в ожидании писателей), поскольку формально он достигает рандеву сам с собой. Именно поэтому попытки использовать select/poll для определения писателем наличия читателя безуспешны.
На мой взгляд (если у Вас на самом деле схема читатель-писатели (несколько писателей тоже достаточно разумный подход)), писатель должен открывать FIFO с O_WRONLY
. Тогда можно сделать таймаут ожидания читателя в момент open()
.
Что же касается непосредственно упомянутого в вопросе write()
с таймаутом, то это, конечно же, можно сделать аналогичным способом (signal/alarm). Только вот, как мне представляется, смысл тут будет несколько другой, а именно, мы будем отлавливать не отсутствие читателя (если он накрылся, то при вызове write()
получим SIGPIPE), а его нежелание читать.
Вот простой пример с ожиданием читателя в течении 1 сек. и отладочной печатью:
// fifow.c (gcc / g++)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define fatal(msg) ({fprintf(stderr,"%ld %s: %m\n",(long)getpid(),msg); exit(-1);})
#define BUFSIZE 4096
static void sigh (int s) { puts("catch alarm"); };
int
openfifow (char *fname)
{
// чуть подправил для красивости
#ifdef __cplusplus
struct sigaction act = {0}, old;
act.sa_handler = sigh;
#else
struct sigaction act = {.sa_handler = sigh}, old;
#endif
sigaction(SIGALRM, &act, &old);
int sec = alarm(1);
int fd = open(fname, O_WRONLY);
if (fd < 0) {
if (errno == EINTR)
perror("openfifow");
else
fatal("openfifow");
} else
printf("openfifow: %d\n", fd);
alarm(sec ? sec - 1 > 0 ? sec - 1 : 1 : 0);
sigaction(SIGALRM, &old, 0);
return fd;
}
int
main (int ac, char *av[])
{
char *fifoname = av[1]? : (char *)"fifotst";
printf ("fifow %ld started\n",(long)getpid());
if (mkfifo(fifoname,0666) && errno != EEXIST)
fatal("mkfifo");
char buf[BUFSIZE];
int l, out = -1;
signal(SIGPIPE, SIG_IGN); // иначе надо обрабатывать сигнал,
// когда читатель отвалил, а мы вызываем write()
while (puts("enter"), fgets(buf, BUFSIZE, stdin)) {
if (out < 0)
if ((out = openfifow(fifoname)) < 0)
continue;
if ((l = write(out, buf, strlen(buf))) <= 0) {
close(out);
out = -1;
printf("write: %d %m\n", l);
}
}
}
Если что-то непонятно, спрашивайте.