É possível que o CMD.EXE libere um arquivo de saída redirecionado antes da saída de todos os subprocessos?

3

Eu tenho um programa que lança outras instâncias de si mesmo. Cada instância redireciona o fluxo de saída padrão para um arquivo diferente. Estou tendo um problema com a seguinte cadeia de eventos:

  1. Um arquivo BAT é executado que contém o comando my_program.exe > output_launcher.txt
  2. my_program.exe inicia mais instâncias usando os comandos my_program.exe > output_1.txtemy_program.exe > output_2.txt
  3. A instância original ( my_program.exe > output_launcher.txt) sai enquanto as duas instâncias iniciadas ( my_program.exe > output_1.txte my_program.exe > output_2.txt) continuam em execução.
  4. O mesmo arquivo BAT do # 1 é executado novamente.
  5. A nova instância de my_program.exe > output_launcher.txtfalha com o erro "O processo não pode acessar o arquivo porque está sendo usado por outro processo".

Não recebo o erro se o arquivo BAT do nº 1 não redirecionar a saída e não recebo o erro se as duas instâncias iniciadas forem encerradas antes de executar o arquivo BAT pela segunda vez.

Portanto, suponho que o CMD.EXE mantenha direitos exclusivos para o arquivo output_launcher.txt até que todos os subprocessos sejam concluídos.

Primeiro de tudo, isso é uma boa suposição?

O que eu gostaria que acontecesse é que o CMD.EXE renuncie a seus direitos a output_launcher.txt quando a instância original existir no nº 3, pois cada subprocesso está redirecionando para seu próprio arquivo.

Isso é possível ao redirecionar a saída padrão? A melhor alternativa em que posso pensar seria realmente aceitar o local do arquivo de log como um argumento da linha de comando e gravar no arquivo diretamente do meu programa, em vez de redirecionar a saída padrão. Isso envolveria muito mais trabalho para mim, portanto, eu gostaria de evitar esse caminho, se possível.

Obrigado!

EDIT: Parece a linha de comando real que a primeira instância usa para iniciar as instâncias adicionais start cmd /C "call my_program.exe > output_1.txt". Depois passo esse comando para a função "system ()" (my_program.exe está escrito no MSDN C).

Talvez eu possa iniciar as instâncias adicionais de uma maneira diferente que possa ajudar?

BimmerM3
fonte
pode ajudar as pessoas se você incluir apenas um demo bat e até mesmo um código-fonte exe demo. e stackoverflow pode ser bom btw,
barlop

Respostas:

1

Após alguns testes breves, eu diria que sua suposição parece correta. Se você deseja verificar isso, recomendo o Process Hacker . (Existe um botão "Downloads" na parte superior; tenha cuidado, pois os anúncios estão mostrando links de download incorretos.) Vá para Hacker, Encontre alças ou DLLs ... (Ctrl-F)

Usando isso, você pode verificar facilmente o que está usando o arquivo e, ao executar novamente a pesquisa, pode verificar quando o arquivo é liberado.

Espero que o Process Explorer também possa fazer isso de maneira semelhante.

Observe que é melhor gravar um nome de arquivo exclusivo ... considere isso: em vez de output_1.txt a primeira chamada secundária e output_2.txt a segunda chamada secundária, verifique quais arquivos existem. Em seguida, suba mais alto para não sobrescrever um arquivo ou esbarrar em problemas porque não é possível anexar porque o arquivo está em uso. Sistemas operacionais e linguagens de programação frequentemente fornecem funcionalidade para gerar um nome de arquivo exclusivo.

Convém gravar em muitos arquivos temporários e combiná-los em menos arquivos. Se essa ideia faz muito sentido, ou mesmo nenhuma, pode depender do seu projeto e de como você as aborda.

Se você possui o código fonte para program.exe, em vez de executar "program.exe> ​​filename", basta usar "program.exe filename". Coloque o código no seu programa para gravar no arquivo rapidamente e feche o arquivo para que ele não seja mais retido quando não houver uma gravação ativa. (Um processo mais completo pode até executar alguns "bloqueios" ... já que você está executando várias cópias do programa, que podem realmente valer a pena investir.) Em vez de chamar printf (), use uma função personalizada que apenas chama printf () se não houver um arquivo de saída especificado, caso contrário, ele gravará em um arquivo. Então, em vez de precisar alterar todas as suas chamadas printf () toda vez que você altera o arquivo de saída, basta alterar o valor de uma variável que é passada para sua função de saída personalizada. Sei que você disse que isso pode não ser preferível devido à necessidade de levar mais tempo. No entanto, informarei que eu pessoalmente economizei muito tempo e esforço depois de criar essa abordagem. Eu vejo isso como a boa solução a longo prazo.

Ou considere usar a funcionalidade de log do sistema operacional. Isso pode ser feito executando um comando na linha de comando: No Unix, execute "logger"; no MS Windows, execute EventCreate . Deve haver maneiras de fazer isso diretamente da sua escolha de linguagem de programação (MSDN C, como você observou). Isso pode não ser ideal se sua saída for longa ou se você estiver preocupado com a bagunça dos logs do sistema operacional. (Sei que alguns locais têm monitoramento ativo dos logs do SO).

TOOGAM
fonte
Obrigado pela resposta detalhada. Parece que a melhor opção é pegar um local de arquivo de log e abrir / imprimir / fechar o arquivo diretamente do meu programa, em vez de confiar no CMD.exe para redirecionar a saída.
BimmerM3
0

É uma suposição razoável.

1) Verifique se o arquivo não está aberto em nenhum outro aplicativo. Uma maneira razoável de fazer isso seria tentar renomear os arquivos enquanto o aplicativo .bat não estiver em execução. Se isso falhar, algum outro aplicativo está mantendo o arquivo aberto.

2) Você pode tentar usar o Operador Anexar em >>vez de >e me dizer o que acontece?

Junkiebev
fonte
1) O arquivo não está aberto em nenhum outro aplicativo. 2) O operador Anexar tem o mesmo comportamento.
BomM3 # 13/15
Eu adicionei um pouco mais de informação no post principal que pode ajudar.
BomM3 # 13/15