c - 使用信号和 sigpipe

标签 c process pipe signals sigpipe

我正在做一项作业,涉及编写一个程序来使用 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 表示管道没有读取器——如果管道现在没有读取器,它将永远不会有读取器。 (想一想:没有读卡器的管道怎么会有读卡器?这不可能!)

您的问题是您正在关闭管道的另一端。解决这个问题,不用担心 SIGPIPESIGPIPE 只是症状。

编辑:这里有两个问题需要回答。如果您不能回答两个这些问题,那么就不要费心处理SIGPIPE

  1. 什么会导致我的程序接收到 SIGPIPE 接收 SIGPIPE 的唯一方法是管道的读取端关闭。如果读取进程崩溃,或者如果它被编程为关闭管道,就会发生这种情况。如果您正在编写网络服务器,或与未知进程通信,这可能很常见。但是,如果您编写的两个程序都在本地运行,则可能表明存在编程错误。

  2. 当我的程序捕获到 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/

相关文章:

c - 图是否连通!福特富尔克森的C语言

android - PackageManager 的 applicationInfo.name 始终为 null

python - 这有可能吗?从一个python shell发送命令/对象到另一个?

c++ - 如何在 bash 中使用管道在 C++ 中使用 getenv() 访问文件?

c - 有效地使用 cuda 共享内存来存储字符

c - 如何从\n 分隔文件中读取字符串

c - 从链表中正确删除元素?指针的内存错误

c++ - 通过 Windows 管道写入进程 STDIN

process - 我们应该跟踪代码以外的东西的缺陷吗?

c++ - 使用 tcp 套接字复制损坏的管道错误