我正在做一项作业,涉及编写一个程序来使用 fork(进程)、信号和选择来处理数据(计算 pi)。
我现在正在处理信号,我想我想做的是使用 SIGPIPE,所以如果程序捕获它,它会尝试再次写入管道(如果进程试图写入管道没有读者,它将被发送 SIGPIPE)。
我在 main() 中使用 fork() 通过将它们发送到辅助函数来为每个进程分配相同的工作。
void worker(int id) {
.... (this piece of code is not relevant)
if(write(pfd[id][1], &c, sizeof(c)) == -1)
printf("Error occurred: %s\n",strerror(errno));
}
如何在此函数中实现信号以捕获 SIGPIPE 并使其再次写入管道?
谢谢!
最佳答案
通常情况下,不是捕获 SIGPIPE
而是忽略它,这会导致 write
失败并返回 EPIPE
而不是静默终止您的程序。
但是:如果您在写入管道时收到 SIGPIPE
,则不要重试。它永远不会工作。 SIGPIPE
表示管道没有读取器——如果管道现在没有读取器,它将永远不会有读取器。 (想一想:没有读卡器的管道怎么会有读卡器?这不可能!)
您的问题是您正在关闭管道的另一端。解决这个问题,不用担心 SIGPIPE
。 SIGPIPE
只是症状。
编辑:这里有两个问题需要回答。如果您不能回答两个这些问题,那么就不要费心处理SIGPIPE
。
什么会导致我的程序接收到
SIGPIPE
? 接收SIGPIPE
的唯一方法是管道的读取端关闭。如果读取进程崩溃,或者如果它被编程为关闭管道,就会发生这种情况。如果您正在编写网络服务器,或与未知进程通信,这可能很常见。但是,如果您编写的两个程序都在本地运行,则可能表明存在编程错误。当我的程序捕获到
SIGPIPE
时会做什么?如果您正在编写一个使用管道与服务器通信的客户端进程,那么什么是你应该用SIGPIPE
做什么?您不能再试一次,而且客户端通常不能重新启动它们所连接的服务器。只需执行明智的默认操作,然后让SIGPIPE
终止您的程序。但是,如果服务器正在向它控制的客户端发送数据并获得SIGPIPE
,它可以重新启动客户端。但这可能是一个非常糟糕的主意——例如,如果客户端是确定性的,它只会再次崩溃,而您最终会陷入无限循环,而不是简单的崩溃。
所以这里的一般格言是“只捕获您准备好处理的错误。”不要仅仅为了完整性而捕获错误。就让他们让你的程序崩溃,或者导致运行失败,你可以稍后回去调试。
代码片段:这是我的一个项目中的一段代码。如果您运行它,SIGPIPE
将不会终止您的进程。相反,write
将生成一个 EPIPE
错误。如果您正在编写网络服务器,那么 EPIPE
是客户端可能突然断开连接的一种可能方式。
void
ignore_sigpipe(void)
{
struct sigaction act;
int r;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
act.sa_flags = SA_RESTART;
r = sigaction(SIGPIPE, &act, NULL);
if (r)
err(1, "sigaction");
}
关于c - 使用信号和 sigpipe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7774569/