如何忽略 nim 中的 "broken pipe" 异常

How to ignore "broken pipe" exception in nim

我正在编写一个 CLI 程序,当我执行像 program | head 这样的二进制文件时,我得到:

Error: unhandled exception: errno: 32 `Broken pipe` [IOError]

我想消除这个异常并尝试添加:

import posix
signal(SIG_PIPE, SIG_IGN)

在我的主要程序中,但这并没有消除错误。该程序使用 threadspool,调用另一个过程来分析输入行池。 (我不知道这是否与问题相关)

更新:

/Users/telatina/miniconda3/nim/lib/pure/concurrency/threadpool.nim(377) slave
/Users/telatina/git/nim-stuff/orf/src/porfidus.nim(307) parseArrayWrapper
/Users/telatina/git/nim-stuff/orf/src/porfidus.nim(247) parseArray
/Users/telatina/miniconda3/nim/lib/system/io.nim(155) checkErr
/Users/telatina/miniconda3/nim/lib/system/io.nim(138) raiseEIO
Error: unhandled exception: errno: 0 `Undefined error: 0` [IOError]

使用 nim 1.2.6 和以下程序(不要认为它是好的风格):

import os, posix, threadpool
signal(SIG_PIPE, SIG_IGN)

proc noise =
  for i in 0 ..< int(1e6):
    echo i

threadpool.spawn noise()
threadpool.spawn noise()
threadpool.sync()

当 运行 如下所示时,它明显忽略了 EPIPE 并且显然是从多个线程打印(因为看到了两个 60s,然后在两个线程到达循环末尾时出现延迟):

$ ./brokenpipe |grep -m2 -F 60
60
60

注释掉 signal 调用后,最后一条命令引发错误:

$ ./brokenpipe |grep -m2 -F 60
60
60
Traceback (most recent call last)
/home/jfondren/.choosenim/toolchains/nim-1.2.6/lib/pure/concurrency/threadpool.nim(377) slave
/home/jfondren/nim/learn/brokenpipe.nim(8) noiseWrapper
/home/jfondren/nim/learn/brokenpipe.nim(6) noise
/home/jfondren/.choosenim/toolchains/nim-1.2.6/lib/system/io.nim(648) echoBinSafe
SIGPIPE: Pipe closed.

因此您的解决方案似乎有效,您确实需要一个它未解决的问题的最小示例。

基于@julian-fondren 的回答和您的代码,我能够复制您的错误。

import os, posix, threadpool
signal(SIG_PIPE, SIG_IGN)

proc noise =
  for i in 0 ..< int(1e6):
    stdout.write($i & '\n')

threadpool.spawn noise()
threadpool.spawn noise()
threadpool.sync()

对于跟随者。

您也在代码中使用了 stdout.writemay throw an IO Exception
由于您使用 SIG_IGN 线程在接收到 SIG_PIPE 时不会停止 运行,而是继续在损坏的管道上调用 stdout.write,从而引发异常。

为了解决这个问题,我找到了三个选项

  1. 处理异常

    这是最通用的解决方案,适用于您的代码因“错误:未处理的异常”而崩溃的任何情况

    to handle an exception in Nim 使用 tryexcept.

stdout.write($i & '\n') 变为

try:
  stdout.write($i & '\n')
except IOError:
  #handle it by ending the program
  quit()
  #or ignore it with
  #discard
  1. 处理信号 在我的机器上使用 SIG_DFL 会导致线程静默终止,从而按照您的意愿运行,但这取决于平台。所以你也可以注册你自己的信号处理程序(抱歉丑陋的造型)
#signal(SIG_PIPE,SIG_DFL)
signal(SIG_PIPE,cast[typeof(SIG_IGN)](proc(signal:cint) =
    stderr.write("handled sigpipe\n")
    quit()
  ))
  1. 就用echo echo,不像 stdout.write 不会抛出异常,所以对于这种情况,这可能是最简单的修复方法