如何确保 popen()ed 进程在退出时运行析构函数?
如果我有一个管道来运行某些命令,则管道命令需要进行一些清理,但是,如果启动管道的进程出现错误,则管道命令不会进行清理。在这种情况下,管道命令是否收到 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);
}
If I have a pipe to run some command, the piped command needs to do some cleanup, however, if the processes that started the pipe has an error, the piped command is not cleaning up. Is the piped command getting SIGPIPE in this case? How can I ensure cleanupPipe destructor is always run? When the errorOccurred exception is thrown, I am seeing that cleanupPipe destructor is not run. I have SIGPIPE handler set up to throw an exception, so if SIGPIPE is the result, I would expect my destructor to be run when the SIGPIPE results in thrown exception unwinding the stack.
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在信号处理程序中引发异常是一个非常糟糕的主意。信号处理程序必须是异步安全的。更糟糕的是,信号处理程序运行的执行线程本质上与主线代码不同。最好使信号处理程序保持较小且非常原始。例如,让 SIGPIPE 处理程序设置一些易失性全局变量来指示 SIGPIPE 发生,并在主线代码中将其作为错误条件进行测试。
其他一些注释:
popen
、pclose
和write
等 C 函数时,您应该检查返回状态。您在调用popen
或pclose
时没有这样做,至少在示例代码中没有。附录
也许比为 SIGPIPE 创建一个设置某些全局变量的处理程序更好的是,将 SIGPIPE 的处理程序设置为忽略,然后检查对管道的写入是否有 EPIPE 错误。
Throwing an exception in a signal handler is a very bad idea. Signal handlers must be asynchronous-safe. To make matters worse, signal handlers run in which is essentially a different thread of execution than your mainline code. It is best to keep your signal handlers small and very primitive. For example, make the SIGPIPE handler set some volatile global variable that indicates that SIGPIPE occurred and test for that as an error condition in your mainline code.
A couple of other comments:
popen
,pclose
, andwrite
. You aren't doing so on your call topopen
orpclose
, at least not in the sample code.class Cleanup
? The constructor receives an already-constructedFILE
pointer, but the destructor destroys it viapclose
. IMO it would be better if the constructor callspopen
, taking the command string as an argument to the constructor.Addendum
Perhaps even better than creating a handler for SIGPIPE that sets some global variable is to set the handler for SIGPIPE to ignore, and then check for an EPIPE error from your writes to the pipe.