如果我有一个管道来运行某个命令,则管道命令需要进行一些清理,但是,如果启动管道的进程有错误,则管道命令不会清除。在这种情况下,管道命令是否获得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);
}
答案 0 :(得分:3)
在信号处理程序中抛出异常是一个非常糟糕的主意。信号处理程序必须是异步安全的。更糟糕的是,信号处理程序运行的主要是与主线代码不同的执行线程。最好保持信号处理程序小而且非常原始。例如,使SIGPIPE处理程序设置一些易失性全局变量,指示发生了SIGPIPE,并在主线代码中将其作为错误条件进行测试。
其他几条评论:
popen
,pclose
和write
等C函数时,您应该检查返回状态。在您致电popen
或pclose
时,您没有这样做,至少在示例代码中没有。class Cleanup
中的不对称?构造函数接收已经构造的FILE
指针,但析构函数通过pclose
销毁它。如果构造函数调用popen
,将命令字符串作为构造函数的参数,IMO会更好。 <强>附录强>
也许比为SIGPIPE创建设置一些全局变量的处理程序更好的是设置SIGPIPE的处理程序忽略,然后检查写入管道的EPIPE错误。