我正在进行一项任务,包括使用fork(进程),信号和选择编写程序来处理数据(计算pi)。
我现在正在处理信号,我认为我想要做的是使用SIGPIPE,所以如果程序捕获它,它会尝试再次写入管道(如果进程试图写入管道,没有读者,它将被发送给SIGPIPE)。
我在main()中使用fork()通过将每个进程发送到worker函数来为每个进程分配相同的工作。
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并使其再次写入管道?
谢谢!
答案 0 :(得分:10)
通常情况下,不会抓住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");
}