写入 `stderr` 时冻结
Freeze when writing to `stderr`
在我的程序中,在这种情况下写入 stderr 时有时会卡住:
- 程序启动(例如从终端)
- 程序分叉两次并使用 execvp 以不同参数启动每个进程(原始文件从
/proc/self/exe
读取)
- 第一个启动的程序退出。
- 现在分叉的两个进程还在运行
- 关闭终端第一个程序启动
- 几次尝试使用
fprintf
写入 stderr
工作,在某些时候我会完全锁定我的程序。调试器告诉我它的 fprintf.
这里发生了什么?我已经尝试过将 SIG_IGN
放在 SIGPIPE
上,以防止程序在没有人再监听管道时立即崩溃。但是现在我被卡住了(冻结的行为是一样的,有 SIG_IGN
和没有它)。
感谢任何帮助。
简而言之shell:系统会向您发送程序信号,以免您遇到问题。你忽略了那些信号。坏事发生了。
当你的父程序是 运行 时,它有 stdin (fd 0)、stdout (fd 1) 和 stderr (fd 2) 连接到 shell 的 TTY 运行 你(终端)。这些功能很像管道。当您关闭终端时,这些 fds 仍然挂起,另一端没有人能够与它们通信。
起初,没有什么不好的事情发生。您写入 stderr,标准库缓存这些写入。没有执行系统调用,所以没问题。
但是随后缓冲区填满,stdlib 尝试刷新它们。当它这样做时,它会填满管道或 TTY 的内核缓冲区。起初,这也很好用。然而,这些缓冲区迟早也会被填满。发生这种情况时,内核会暂停您的进程并等待有人从这些管道的另一端读取数据。但是,由于您关闭了终端,因此没有人会这样做,并且您的程序将无限期暂停。
避免此问题的标准方法是断开 0-2 文件描述符与控制 TTY 的连接。我不想告诉你如何去做,我想建议你在这里尝试做的事情,运行 一个程序,它完全与 TTY 断开连接,有一个名称:daemonizing。
查看 this 问题以了解有关如何执行此操作的更多详细信息。
编辑添加:
从您的功能中不清楚您正在 execve
编写的程序是否是您自己的。如果不是,请注意许多用户程序并非设计为 运行 作为守护进程。最明显的警告是,如果未连接到任何 TTY 的程序打开 TTY 文件,并且除非它传递 O_NOCTTY
到 open
,否则该 TTY 将成为该程序的控制 TTY。根据具体情况,这可能会导致意外结果。
在我的程序中,在这种情况下写入 stderr 时有时会卡住:
- 程序启动(例如从终端)
- 程序分叉两次并使用 execvp 以不同参数启动每个进程(原始文件从
/proc/self/exe
读取) - 第一个启动的程序退出。
- 现在分叉的两个进程还在运行
- 关闭终端第一个程序启动
- 几次尝试使用
fprintf
写入stderr
工作,在某些时候我会完全锁定我的程序。调试器告诉我它的 fprintf.
这里发生了什么?我已经尝试过将 SIG_IGN
放在 SIGPIPE
上,以防止程序在没有人再监听管道时立即崩溃。但是现在我被卡住了(冻结的行为是一样的,有 SIG_IGN
和没有它)。
感谢任何帮助。
简而言之shell:系统会向您发送程序信号,以免您遇到问题。你忽略了那些信号。坏事发生了。
当你的父程序是 运行 时,它有 stdin (fd 0)、stdout (fd 1) 和 stderr (fd 2) 连接到 shell 的 TTY 运行 你(终端)。这些功能很像管道。当您关闭终端时,这些 fds 仍然挂起,另一端没有人能够与它们通信。
起初,没有什么不好的事情发生。您写入 stderr,标准库缓存这些写入。没有执行系统调用,所以没问题。
但是随后缓冲区填满,stdlib 尝试刷新它们。当它这样做时,它会填满管道或 TTY 的内核缓冲区。起初,这也很好用。然而,这些缓冲区迟早也会被填满。发生这种情况时,内核会暂停您的进程并等待有人从这些管道的另一端读取数据。但是,由于您关闭了终端,因此没有人会这样做,并且您的程序将无限期暂停。
避免此问题的标准方法是断开 0-2 文件描述符与控制 TTY 的连接。我不想告诉你如何去做,我想建议你在这里尝试做的事情,运行 一个程序,它完全与 TTY 断开连接,有一个名称:daemonizing。
查看 this 问题以了解有关如何执行此操作的更多详细信息。
编辑添加:
从您的功能中不清楚您正在 execve
编写的程序是否是您自己的。如果不是,请注意许多用户程序并非设计为 运行 作为守护进程。最明显的警告是,如果未连接到任何 TTY 的程序打开 TTY 文件,并且除非它传递 O_NOCTTY
到 open
,否则该 TTY 将成为该程序的控制 TTY。根据具体情况,这可能会导致意外结果。