Как обеспечить, чтобы процесс popen()ed запускал деструкторы при выходе?
Если у меня есть канал для запуска какой-либо команды, команда piped должна выполнить некоторую очистку, однако, если процессы, запустившие канал, имеют ошибку, команда piped не очищает. Команда piped получает SIGPIPE в этом случае? Как я могу убедиться, что деструктор cleanupPipe всегда запущен? Когда выдается исключение errorOccurn, я вижу, что деструктор 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);
}
1 ответ
Бросать исключение в обработчик сигнала - очень плохая идея. Обработчики сигналов должны быть асинхронно безопасными. Что еще хуже, работают обработчики сигналов, в которых поток выполнения по сути отличается от вашего основного кода. Лучше всего, чтобы ваши обработчики сигналов были маленькими и очень примитивными. Например, заставьте обработчик SIGPIPE установить некоторую изменчивую глобальную переменную, которая указывает, что произошел SIGPIPE, и проверьте это как условие ошибки в вашем основном коде.
Пара других комментариев:
- Вы должны проверить статус возврата при работе с функциями C, такими как
popen
,pclose
, а такжеwrite
, Вы не делаете это по вашему призывуpopen
или жеpclose
по крайней мере, не в примере кода. - Почему асимметрия в
class Cleanup
? Конструктор получает уже построенныйFILE
указатель, но деструктор уничтожает его черезpclose
, ИМО было бы лучше, если конструктор вызываетpopen
, принимая командную строку в качестве аргумента для конструктора.
добавление
Возможно, даже лучше, чем создание обработчика для SIGPIPE, который устанавливает некоторую глобальную переменную, - установить обработчик для игнорирования SIGPIPE, а затем проверить наличие ошибки EPIPE при записи в канал.