Назад | Перейти на главную страницу

Как избежать ошибок «используется другим процессом» при передаче вывода через программу?

В среде Windows гарантируются ли исполняемые программы, используемые для обработки конвейерного вывода, уникальными задачами, если они вызываются из разных сред CMD?

Например, предположим, что script1.cmd содержит эту строку:

echo "some logging information" | my_pipe_program >> logfile1.txt

Также есть script2.cmd, который содержит эту строку:

echo "some other information" | my_pipe_program >> logfile2.txt

Если скрипты script1 и script2 запускаются одновременно, будет ли Windows вызывать отдельные экземпляры my_pipe_program.exe?

Я получаю спорадические ошибки, когда командный сценарий завершается с ошибкой «Процесс не может получить доступ к файлу, потому что он используется другим процессом». Эта ошибка всегда возникает сразу после строки, которая проходит через my_pipe_program.exe.
Это заставляет сценарий CMD останавливаться прямо в этом месте, оставляя окно CMD открытым.

Конфликт может быть с my_pipe_program.exe или с logfile2.txt. Программа my_pipe_program.exe используется в нескольких файлах CMD, которые потенциально могут запускаться одновременно. Файл журнала уникален для файла CMD, поэтому кажется, что он менее вероятен, если Windows не закрывает его после того, как файл CMD существует. Есть ли способ диагностировать проблему и исправить ошибку?

Связанный вопрос - есть ли способ перехватить и обработать ошибку «... используется другим процессом» и предотвратить прерывание файла CMD?

Похоже, проблема в том EXE и как он обрабатывает вызовы на одной машине, работающей одновременно в памяти. Включение расширенного ведения журнала на этом уровне для сбора подробных сведений или трассировки стека при эмуляции параллельных запусков в памяти с одного и того же компьютера, как и при возникновении проблемы, может быть лучшим для наиболее точного ответа ЗАЧЕМ он делает это.

Смотрите мой ответ здесь (Суперпользователь) на SuperUser с на днях, как убить процесс пакетом, если CMD или BAT файл ЛАЙК определенное имя.

Вы можете включить что-то вроде этого, чтобы проверить и посмотреть, не работает ли что-то в течение определенного периода времени с этими именами командных файлов и kill, но вам нужно будет посмотреть другие параметры в WMIC чтобы узнать, есть ли таймер и т. д., если это сработает в вашем случае. Исправление EXE логика на этом уровне и улавливание ошибки и окончание может быть лучше, если вы контролируете на этом уровне.


ДОПОЛНИТЕЛЬНЫЕ ИДЕИ

Простым решением может быть создание файла блокировки при запуске пакетного файла CMD, чтобы все сценарии, запускающие тот же EXE с того же компьютера сначала проверьте, существует ли файл блокировки, если он существует, затем завершите скрипт (или, возможно, сделайте паузу на столько минут, а затем снова проверьте и т. д.).

Вы можете просто завершить сценарий [GOTO locked] или приостановите его на столько секунд, а затем перейдите к этой процедуре [GOTO lockedrecheck] и еще раз проверьте, завершен ли другой процесс, и удалите файл, если этого достаточно в вашем случае.

Если файл блокировки не существует, он создаст файл, затем запустит процесс и, когда это будет сделано, удалите файл блокировки, чтобы другие процессы могли работать (пример ниже).

Вы также можете добавить 2<&1 в конец файла журнала, чтобы получить более подробную информацию, если EXE позволяет захватывать его таким образом, где иначе не было бы (пример логики сценария ниже).

ПРИМЕР БЛОКИРОВКИ ФАЙЛА (завершите его или приостановите и проверьте еще раз)

<ABOVE LOGIC>
<ABOVE LOGIC>
<ABOVE LOGIC>
<ABOVE LOGIC>

:SetLockFile
::SET check for, and create lock file to ensure concurrent runs aren't possible
SET lockfile=\\server\share\lockfiles\my_pipe_program.lck
IF EXIST %lockfile% GOTO locked
::IF EXIST %lockfile% GOTO lockedrecheck 
ECHO This file is locked until current %~nx0 script ends or finishes using the EXE >> %lockfile%

ECHO "some logging information" | my_pipe_program >> %logfile% 2<&1

<More Logic>
<More Logic>
<More Logic>
<More Logic>

:end
ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> %logfile%
ECHO End: %date% at %time%                       >> %logfile%
ECHO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> %logfile%
DEL /Q /F "%lockfile%"
ENDLOCAL
GOTO EOF

:locked
:: Come here to end the script since the lock file does exist
ECHO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>> %logfile%
ECHO LOCKED FILE: %~nx0 - %date% at %time%: FILE IS IN USE AND LOCKED                             >> %logfile%
ECHO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>> %logfile%
ENDLOCAL
GOTO EOF

:lockedrecheck
:: Come here to Pause the script with a loopback ping to nul for 3 minutes or roughly 180 seconds
PING 127.0.0.1 -n 180 > nul
GOTO :SetLockFile

2<&1 пример

echo "some logging information" | my_pipe_program >> logfile1.txt 2<&1