写入“stderr”时冻结

Nid*_*ger 2 c linux freeze stderr

在我的程序中,在这种情况下写入 stderr 时有时会冻结:

  1. 程序启动(例如从终端)
  2. 程序分叉两次并使用 execvp 以不同的参数启动每个进程(原始文件是从 读取的/proc/self/exe
  3. 第一个启动的程序退出。
  4. 现在两个fork进程仍在运行
  5. 关闭终端第一个程序已启动
  6. 尝试使用fprintf写入来stderr工作,在某些时候我的程序会完全锁定。调试器告诉我它的 fprintf。

这里发生了什么?我已经尝试过的是,一旦没有人再监听管道,就可以防止程序崩溃SIG_IGN。但现在我陷入了困境(无论有没有SIGPIPE冻结,冻结的行为都是一样的)。SIG_IGN

任何帮助表示赞赏。

Sha*_*esh 5

简而言之:系统向您的程序发送信号以帮助您避免出现问题。你忽略了这些信号。坏事发生了。

当你的父程序运行时,它有 stdin (fd 0)、stdout (fd 1) 和 stderr (fd 2) 连接到运行你的 shell(终端)的 TTY。它们的功能很像管道。当您关闭终端时,这些 fd 会处于挂起状态,另一端没有人能够与它们通信。

起初,没有什么不好的事情发生。您写入 stderr,标准库会缓存这些写入。没有执行系统调用,所以没有问题。

但随后缓冲区已满,stdlib 会尝试刷新它们。当它这样做时,它会填充管道或 TTY 的内核缓冲区。起初,这也很好用。然而,这些缓冲区迟早也会被填满。当发生这种情况时,内核会挂起您的进程并等待有人从这些管道的另一端读取数据。然而,自从您关闭了终端后,就没有人会这样做了,并且您的程序将无限期暂停。

避免此问题的标准方法是断开 0-2 个文件描述符与控制 TTY 的连接。我不想告诉您如何做到这一点,而是建议您在这里尝试执行的操作是运行一个程序,使其与 TTY 完全断开连接,并有一个名称:守护进程。

查看问题以了解有关如何执行此操作的更多详细信息。

编辑添加:

从您的功能来看,并不清楚您正在execve运行的程序是否是您自己的。如果不是,请注意许多用户程序并不是设计为作为守护程序运行的。最明显的警告是,如果未连接到任何 TTY 的程序打开 TTY 文件,并且除非它传递O_NOCTTYopen,否则该 TTY 将成为该程序的控制 TTY。根据具体情况,这可能会导致意想不到的结果。