父接收SIGPIPE通过FIFO管道向中止的子进程发送字符。 我试图使用select()函数来避免这种情况。在附带的示例代码中, 即使在管道另一端的子节点终止后,select()也会重新运行OK。 测试中 RedHat EL5(Linux 2.6.18-194.32.1.el5) GNU C库稳定版本2.5 任何帮助赞赏。骗过你
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
static void sigpipe_fct();
main()
{
struct stat st;
int i, fd_out, fd_in, child;
char buf[1024];
#define p_out "/tmp/pout"
signal(SIGPIPE, sigpipe_fct);
if (stat(p_out, &st) != 0) {
mknod(p_out, S_IFIFO, 0);
chmod(p_out, 0666);
}
/* start receiving process */
if ((child = fork()) == 0) {
if ((fd_in = open(p_out, O_RDONLY)) < 0) {
perror(p_out);
exit(1);
}
while(1) {
i = read(fd_in, buf, sizeof(buf));
fprintf(stderr, "child %d read %.*s\n", getpid(), i, buf);
lseek(fd_in, 0, 0);
}
}
else {
fprintf(stderr,
"reading from %s - exec \"kill -9 %d\" to test\n", p_out, child);
if ((fd_out = open(p_out, O_WRONLY + O_NDELAY)) < 0) { /* output */
perror(p_out);
exit(1);
}
while(1) {
if (SelectChkWrite(fd_out) == fd_out) {
fprintf(stderr, "SelectChkWrite() success write abc\n");
write(fd_out, "abc", 3);
}
else
fprintf(stderr, "SelectChkWrite() failed\n");
sleep(3);
}
}
}
static void sigpipe_fct()
{
fprintf(stderr, "SIGPIPE received\n");
exit(-1);
}
SelectChkWrite(ch)
int ch;
{
#include <sys/select.h>
fd_set writefds;
int i;
FD_ZERO(&writefds);
FD_SET (ch, &writefds);
i = select(ch + 1, NULL, &writefds, NULL, NULL);
if (i == -1)
return(-1);
else if (FD_ISSET(ch, &writefds))
return(ch);
else
return(-1);
}
答案 0 :(得分:2)
来自Linux select(3)
man page:
当呼叫时,描述符应被视为已准备好写入 无论是否清除,O_NONBLOCK清除的输出功能都不会阻塞 该函数将成功传输数据。
当管道关闭时,它不会阻塞,因此被select
视为“准备好”。
顺便说一句,#include <sys/select.h>
内部有SelectChkWrite()
你的select()
函数形式非常糟糕。
虽然select()
和poll()
都在POSIX标准中,但poll()
比poll()
更老,更有限。一般来说,我建议人们默认使用select()
,如果他们有充分的理由,则只使用{{1}}。 (参见one example。)