Создать временный каталог, который известен во всем мире и который автоматически удаляется (C ++)? - PullRequest
1 голос
/ 25 января 2009

В C ++ у меня есть несколько функций, которые нужно записать во временный каталог. В идеале создается только один временный каталог, в который они все записывают (чтобы минимизировать издержки ввода-вывода). Этот каталог должен автоматически удаляться при выходе из программы.

Однако я не хочу иметь дело с созданием и удалением временного каталога в основной функции, потому что я думаю, что только функции, которые фактически используют каталог, должны отвечать за его создание и удаление. И основная функция не обязательно знает, что временный каталог используется вообще.

Вот что я попробовал (см. Код ниже): функция getTempDir (), которую можно вызывать глобально из любого места, создает каталог только при первом вызове и возвращает имя dir при каждом вызове. При первом вызове он также создает статический boost :: shared_ptr для небольшого объекта DirRemover, чей деструктор удалит каталог. Этот деструктор вызывается автоматически при выходе из программы.

Проблема в том, что он не вызовет деструктор FileRemover при неудачном выходе из программы, или уничтожении и т. Д. Есть ли лучшие решения?

Вот код:

std::string getTempDir(){
  static bool alreadyThere = false;
  static std::string name = "";
  if(!alreadyThere){
    // create dir with
    // popen("mktemp -p /tmp","r")) 
    // and store its name in 'name' 
    removeAtEnd(name);
    alreadyThere = true;
  }
  return name;
}

void removeAtEnd(const std::string& name){
  static boost::shared_ptr<DirRemover> remover(new DirRemover(name));
}

struct DirRemover {
  std::string name;
  DirRemover(const std::string& n) : name(n){}
  ~DirRemover(){
    // remove 'name' dir with popen("rm -r ...")
  }
};

Ответы [ 4 ]

7 голосов
/ 25 января 2009

Использование popen () для выполнения таких вещей, как «rm -r» или «mktemp -p / tmp», - это путь к катастрофе. На мой взгляд, это очень плохой стиль.

Специфично для UNIX: Если вы хотите, чтобы временные файлы исчезали, даже если ваше приложение прерывалось ненормально, тогда лучший способ - немедленно отсоединить временные файлы после их открытия. Ваше приложение по-прежнему будет иметь дескриптор файла, чтобы вы могли работать с файлом. Когда ваше приложение завершается и файловый дескриптор закрывается, файл автоматически удаляется из файловой системы.

Кстати, я вижу, что вы используете Boost. Вы уверены, что Boost.Filesystem не имеет вышеуказанных функций?

2 голосов
/ 25 января 2009

Для Unix:

::signal(SIGINT, sigintHandler);
::signal(SIGKILL, sigkillHandler); //etc

Заставьте эти обработчики помещать событие выхода в очередь событий (или эквивалент) и игнорировать сигнал. Ваше приложение сможет выйти изящно. Однако есть один сигнал (SIGKILL), который нельзя игнорировать. Чтобы справиться с этим, определите наиболее важные ресурсы, которые вы действительно хотите освободить при убийстве (я не уверен, что временный каталог так важен. Просто удалите его при следующем запуске.), И в вашем обработчик, вызовите функцию release в соответствующих синглетонах.

Для уточнения синглетонов . ::signal не может вызывать связанные функции, поэтому ваш обработчик имеет доступ только к одиночным / глобальным переменным. Если ваш дизайн не организовывает вещи с помощью синглетонов (и не должен), вы все равно часто можете взломать это. Например, если у вас есть несколько MainWindows в стеке, вы также можете иметь глобальный вектор указателей на все из них, к которому вы можете обращаться из обработчика, если это необходимо.

Обратите внимание, что для обычных убийств (например, с kill foo) вы получаете SIGQUIT, а не SIGKILL - и SIGQUIT приятно игнорируется. SIGKILL предназначен только для kill -9 foo (в этом случае пользователь может даже не хочет выполнять очистку).

Да, сигналы волосатые.

edit - Мне сообщили, что SIGKILL не только негоден, но и неуловим . И действительно, на SIGKILL мало что можно сделать вменяемым. Удаление временного каталога? Зачем? Этот временный директор был там по причине.

Просто притворитесь, что sigkill - это сбой питания, и восстановитесь при следующем запуске - если только вы не можете сделать конкретный взлом, как говорили другие по поводу отмены связи.

Это то, что я получаю, говоря из моей задницы.

0 голосов
/ 25 января 2009

Пара мыслей:

  • Поддержание минимальной связи : почему бы не создать класс обслуживания, который будет стоять между вашим другим кодом и сведениями о том, где пишется материал и когда он удаляется? Используйте обычный метод синглтона , чтобы убедиться, что он инициализируется только один раз.

  • Страхование удаления : сигнал уже упоминался как способ, позволяющий изящно выполнить очистку в случае SIGFPE, SIGSEGV, SIGTERM и т. Д. Это не поможет событие SIGSTOP или SIGKILL. Тем не менее, существует старый трюк Unix для файлов, где вы создаете файл на диске, затем unlink it --- в этот момент файл все еще используется и фактически не удаляется, но это будет, когда вы запрограммированы освобождает его файловый дескриптор --- и вы получаете автоматическое удаление. Я не знаю, как это будет работать с каталогом, но вы, безусловно, можете заставить его работать со всеми содержащимися в нем файлами. В качестве бонуса (или стоимости, в зависимости от) эти файлы не видны или недоступны для других процессов после вызова unlink.


Добавлено : См. Также:

0 голосов
/ 25 января 2009

Невозможно выполнить очистку, если ваш процесс убит (например, из диспетчера задач).

Другой процесс должен выполнить эту очистку, если ваша программа останавливается. Запустите этот процесс и запустите вашу программу как дочерний процесс. Этот процесс создает временный каталог перед запуском вашей программы и удаляет его после ее завершения.

Хотя это все еще не решает проблему, если ваш процесс обертки будет убит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...