1

如果我有一个管道来运行某些命令,则管道命令需要进行一些清理,但是,如果启动管道的进程有错误,则管道命令不会清理。在这种情况下,管道命令是否获得 SIGPIPE?如何确保 cleanupPipe 析构函数始终运行?当 errorOccurred 异常被抛出时,我看到 cleanupPipe 析构函数没有运行。我设置了 SIGPIPE 处理程序以引发异常,因此如果 SIGPIPE 是结果,我希望我的析构函数在 SIGPIPE 导致抛出异常展开堆栈时运行。

void
testCase() {
  class cleanup {
  public:
    cleanup(FILE *pipe)
      : _pipe(pipe) {
    }
    ~cleanup() {
      ::pclose(_pipe);
    }

  private:
    FILE *_pipe;

  };

  string cmd("runMyCommandImplementationHere argsHere");
  FILE *pipePtr = ::popen(cmd, "w");
  cleanup cleanUpPipe(pipePtr);

  // Normally, write data to pipe until process in pipe gets all the data it
  // needs and exits gracefully.
  for (;;) {
    if (someErrorOccured()) {
      // When this error occurs, we want to ensure cleanupPipe is run in piped
      // process.
      throw errorOccurred(status);
    }
    if (finishedWritingData()) {
      break;
    }
    writeSomeDataToPipe(pipePtr);
  }
}

void
myCommandImplementationHere() {
  class cleaupPipe {
  public:
    cleanupPipe(const string &filename)
      : _filename(filename) {
    }
    ~cleanupPipe() {
      ::unlink(_filename.c_str());
    }

  private:
    string _filename;

  };

  string file("/tmp/fileToCleanUp");
  cleanupPipe cleanup(file);

  doSomeWorkOnFileWhileReadingPipeTillDone(file);
}
4

1 回答 1

3

在信号处理程序中抛出异常是一个非常糟糕的主意。信号处理程序必须是异步安全的。更糟糕的是,信号处理程序运行在与主线代码不同的执行线程中。最好让您的信号处理程序保持小且非常原始。例如,让 SIGPIPE 处理程序设置一些指示 SIGPIPE 发生的易失性全局变量,并在您的主线代码中将其作为错误条件进行测试。

其他一些评论:

  • 在处理诸如 、 和 之类的 C 函数时,您应该检查popen返回pclose状态write。您没有在调用popenor时这样做pclose,至少在示例代码中没有。
  • 为什么不对称class Cleanup?构造函数接收一个已经构造的FILE指针,但析构函数通过pclose. 如果构造函数调用 IMO 会更好popen,将命令字符串作为构造函数的参数。

附录
或许比为 SIGPIPE 创建一个设置一些全局变量的处理程序更好的是,将 SIGPIPE 的处理程序设置为忽略,然后检查您对管道的写入是否存在 EPIPE 错误。

于 2011-08-07T15:23:56.303 回答