Перед удалением проверьте, используется ли файл другим процессом (c, c ++, linux) - PullRequest
1 голос
/ 07 августа 2020

Мне нужно удалить файл (скажем, он называется <file.txt>), когда другой процесс (это из другой программы, которую я вызываю с помощью system("anotherProgram <file.txt>") в моем коде на C ++) завершает его использование.

Моя программа генерирует <file.txt>, передает его внешнему приложению. Это приложение записывает свои шаги в файл журнала, и владелец приложения сказал, что этот файл не нужен приложению после того, как какое-то сообщение (скажем, 'aaa') напечатано в файле журнала.

Я полагаю, что внешнее приложение просто анализирует это <file.txt> и после завершения выводит сообщение 'aaa' в журнал. Итак, я верю, что после этого будет безопасно удалить <file.txt> из моего кода.

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

Но в некоторых случаях я все еще получаю ошибки от этого внешнего приложения, что оно не может найти файл <file.txt>, поэтому я предполагаю, что даже после того, как сообщение 'aaa' напечатано в журнале, приложение все еще пытается использовать <file.txt>.

Я хотел бы знать, если что-то я делаю не так.

PS: Если бы я спал дольше (скажем, 10000 мс), я бы не столкнулся с этой проблемой.

1 Ответ

0 голосов
/ 07 августа 2020

Разумный способ сделать это - передать файл через файловый дескриптор, обычно стандартный ввод.

(Большинство программ поддерживают чтение своего ввода со стандартного ввода, но если этот конкретный не поддерживает, вы по-прежнему можно использовать /proc/self/fd/N для файлового дескриптора N.)

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

В родительском процессе вам просто нужно использовать /proc/self/fd/N для имени файла и не закрывать файл до того, как дочерний будет выполнен . Вы можете отсоединить (удалить) файл, поскольку базовый индексный дескриптор (метаданные и содержимое файла) остается доступным, пока он открыт хотя бы в одном процессе.

Итак, вот схема, которую я бы использовал:

  1. Откройте и создайте целевой файл (используя O_CREAT | O_RDWR или O_CREAT | O_EXCL | O_RDWR, или при использовании stdio, w или w+).

  2. Если файл должен быть удален, когда он больше не нужен, отключите его сейчас.

  3. Создайте содержимое файла.

  4. При использовании stdio, мы хотим сохранить только дескриптор файла, но закрыть поток:

    int fd = dup(fileno(handle));
    fclose(handle);
    

    В противном случае мы предположим, что fd - это дескриптор файла для целевого файла.

  5. Сделайте lseek(newfd, 0, SEEK_SET);, чтобы позиция файла, на которую ссылается дескриптор, находилась в начале файла.

  6. Используйте небольшой буфер, скажем, 32 символа, для печати пути к файловому дескриптору (в дочернем процессе) через snprintf(buffer, sizeof buffer, "/proc/self/fd/%d", fd);

  7. Построить массив строк, соответствующих переход к параметрам программы, где [0] - это имя программы, [1] - первый параметр и так далее; с (char *)0 в качестве последнего параметра. Используйте вышеупомянутый buffer в качестве имени файла.

  8. Call pid = run(binary, argarray);, где argarray - это вышеупомянутый массив строк, а binary - имя двоичного файла для запустить (если находится в каталоге с именем PATH) или его полный путь. (Если он содержит sla sh, он интерпретируется как абсолютный или относительный путь; в противном случае используются каталоги, указанные в переменной среды PATH.)

  9. Если pid == -1 , команда не может быть выполнена; причина в strerror(errno). В противном случае команда выполняется одновременно.

  10. Если вы хотите дождаться завершения другой программы, позвоните reap(pid, NULL) или reap(pid, &status), если вы хотите получить подробную информацию о ее выходе в int status (но не забудьте использовать WIFEXITED(status), WEXITSTATUS(status), et c., Как описано в man 2 waitpid .

Поскольку автомаги c удаление файла обрабатывается заранее, если родительскому процессу больше нечего делать после этого, вместо того, чтобы создавать дочерний процесс, вы можете просто заменить текущий процесс новым процессом, используя только execv(binary, argarray) или execvp(binary, argarray), в зависимости от того, является ли binary путем или только именем исполняемого двоичного файла программы / скрипта.

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