Как обеспечить, чтобы процесс popen () ed запускал деструкторы при выходе? - PullRequest
1 голос
/ 07 августа 2011

Если у меня есть канал для запуска какой-либо команды, команда 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 Ответ

3 голосов
/ 07 августа 2011

Бросить исключение в обработчик сигнала - очень плохая идея. Обработчики сигналов должны быть асинхронно безопасными. Что еще хуже, запускаются обработчики сигналов, которые по сути отличаются потоком выполнения от вашего основного кода. Лучше всего, чтобы ваши обработчики сигналов были маленькими и очень примитивными. Например, заставьте обработчик SIGPIPE установить некоторую изменчивую глобальную переменную, которая указывает, что SIGPIPE произошел, и проверьте это как условие ошибки в вашем основном коде.

Пара других комментариев:

  • Вы должны проверить статус возврата, когда имеете дело с такими функциями C, как popen, pclose и write. Вы не делаете этого при вызове popen или pclose, по крайней мере, в примере кода.
  • Почему асимметрия в class Cleanup? Конструктор получает уже созданный указатель FILE, но деструктор уничтожает его с помощью pclose. IMO было бы лучше, если бы конструктор вызывал popen, принимая командную строку в качестве аргумента для конструктора.

Добавление
Возможно, даже лучше, чем создание обработчика для SIGPIPE, который устанавливает некоторую глобальную переменную, - установить обработчик для игнорирования SIGPIPE, а затем проверить наличие ошибки EPIPE при записи в канал.

...