翻个墙真是糟心-_-
总结得很好!
APUE 中有个类似的例子, 在我看的第二版中是在section15.4.
这个小程序(fig15.18)fork()了之后,父进程每次从stdin中读入一行传给子进程, 后者从这一行中scan出两个整数,算出两数之和并传回给父进程.(编译这个程序需要apue.h和err_sys()的源码,这些书上都有,
网站上也提供了电子版源码. 这里的err_sys()就是打印错误信息并退出.)
#include "apue.h"
static void sig_pipe(int); /* our signal handler */
int
main(void)
{
if (signal(SIGPIPE, sig_pipe) == SIG_ERR)
if (pipe(fd1) < 0 || pipe(fd2) < 0)
if ((pid = fork()) < 0) {
} else if (pid > 0) { /* parent */
while (fgets(line, MAXLINE, stdin) != NULL) {
if (write(fd1[1], line, n) != n)
err_sys("write error to pipe");
if ((n = read(fd2[0], line, MAXLINE)) < 0)
err_sys("read error from pipe");
err_msg("child closed pipe");
line[n] = 0; /* null terminate */
if (fputs(line, stdout) == EOF)
err_sys("fgets error on stdin");
if (fd1[0] != STDIN_FILENO) {
if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
if (fd2[1] != STDOUT_FILENO) {
if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
if (execl("./add2", "add2", (char *)0) < 0)
}
static void
sig_pipe(int signo)
{
printf("SIGPIPE caught\n");
在这里如果子进程exec的add2程序这么写的话,将形成死锁:(以下为前面给出链接的源码包中的 apue.2e/fig15.19)
#include "apue.h"
int
main(void)
{
int int1, int2;
char line[MAXLINE];
while (fgets(line, MAXLINE, stdin) != NULL) {
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
if (printf("%d\n", int1 + int2) == EOF)
err_sys("printf error");
} else {
if (printf("invalid args\n") == EOF)
err_sys("printf error");
}
}
exit(0);
}
问题就在 `if (printf("%d\n", int1 + int2) == EOF)' 这句, 子进程的输出压在了缓冲区里, 父进程收不到,block在了read()上,子进程于是也接收不到父进程进一步的输出,同样卡住了.
解决办法自然可以和前面一样用setvbuf(), 而作者同时还谈到了如果子进程要exec()的是我们不知道其源码的第三方程序该怎么办呢?作者给出的答案是用虚拟终端,(fig19.10, fig19.11, fig19.12, fig19.13)将slave dup到子进程的stdinouterr, 随后父进程再次fork(), 父进程将master里读到的内容输出到原始的stdout,二儿子把原始的stdin的内容输出到master.这其实可以用线程来实现.
除了这个方法之外,还有没有其他节省资源一点的方法?
zhen y於 2017年1月19日星期四 UTC+8下午3時33分13秒寫道: