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

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

Eu tenho um programa que lança outras instâncias dele 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 e contém o comandomy_program.exe > output_launcher.txt
  2. my_program.exe inicia mais instâncias de si mesmo 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) é encerrada 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 nº 1 é executado novamente.
  5. A nova instância my_program.exe > output_launcher.txtfalha com o erro “O processo não pode acessar o arquivo porque ele 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 saírem antes de executar o arquivo BAT pela segunda vez.

Portanto, presumo que CMD.EXE detém direitos exclusivos sobre o arquivo output_launcher.txt até que todos os subprocessos sejam concluídos.

Em primeiro lugar, essa é uma boa suposição?

O que eu gostaria que acontecesse é que o CMD.EXE desista de seus direitos sobre 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 que posso imaginar seria usar a localização do arquivo de log como um argumento de 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, então gostaria de evitar esse caminho, se possível.

Obrigado!

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

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

Responder1

Após alguns breves testes, eu diria que sua suposição parece correta. Se você quiser verificar isso, recomendoHacker de processos. (Há um botão "Downloads" na parte superior; tome cuidado, pois os anúncios mostram links de download ruins.) Vá para Hacker, encontre identificadores 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 pode ser melhor escrever em um nome de arquivo exclusivo... considere o seguinte: em vez de output_1.txt a primeira subchamada e output_2.txt a segunda subchamada, verifique quais arquivos pré-existem. Em seguida, vá mais alto, para não sobrescrever um arquivo ou ter problemas porque não pode anexar porque o arquivo está em uso. Os sistemas operacionais e as linguagens de programação frequentemente fornecem funcionalidade para gerar um nome de arquivo exclusivo.

Talvez você queira gravar em muitos arquivos temporários e depois combiná-los em menos arquivos. Se essa ideia faz muito sentido ou não faz nenhum sentido, pode depender do seu projeto e de como você aborda as coisas.

Se você tiver o código-fonte do program.exe, em vez de executar "program.exe> ​​nome do arquivo", basta usar "nome do arquivo program.exe". Coloque o código em seu programa para gravar no arquivo rapidamente e, em seguida, feche o arquivo para que ele não fique mais retido quando não houver uma gravação ativa. (Um processo mais completo pode até realizar algum "bloqueio"... já que você está executando várias cópias do programa, pode valer a pena investir nisso.) Em vez de chamar printf(), use uma função personalizada que chama apenas printf () se não houver nenhum arquivo de saída especificado, caso contrário, ele grava em um arquivo. Então, em vez de precisar alterar todas as suas chamadas printf() toda vez que você alterar o arquivo de saída, você simplesmente precisa alterar o valor de uma variável que é passada para sua função de saída personalizada. Eu sei que você disse que isso pode não ser preferível devido à necessidade de demorar mais algum tempo. No entanto, direi que pessoalmente economizei muito tempo e esforço depois de criar essa abordagem. Considero que esta é uma boa solução a longo prazo.

Ou considere usar a funcionalidade de registro do sistema operacional. Isso pode ser feito executando um comando na linha de comando: No Unix, execute "logger"; no MS Windows, executeCriar Evento. Deve haver maneiras de fazer isso diretamente a partir 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 em sobrecarregar os logs do sistema operacional. (Eu sei que alguns lugares têm monitoramento ativo de logs do sistema operacional.)

Responder2

É 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 Append >>em vez de >e me dizer o que acontece?

informação relacionada