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

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 contendo o comando my_program.exe > output_launcher.txt
  2. my_program.exe lança mais instâncias de si mesmo usando os comandos my_program.exe > output_1.txt e my_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.txt e my_program.exe > output_2.txt ) continuam sendo executadas.
  4. O mesmo arquivo BAT do # 1 é executado novamente.
  5. A nova instância de my_program.exe > output_launcher.txt falha com o erro "O processo não pode acessar o arquivo porque está sendo usado por outro processo".

Eu não recebo o erro se o arquivo BAT de # 1 não redireciona a saída e não obtenho o erro se as duas instâncias ativadas saírem antes de executar o arquivo BAT pela segunda vez.

Portanto, suponho que o CMD.EXE esteja mantendo os direitos exclusivos do arquivo output_launcher.txt até que todos os subprocessos estejam concluídos.

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

O que eu gostaria de acontecer é que o CMD.EXE desista de seus direitos para output_launcher.txt quando a instância original existir em # 3, já que 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 realmente pegar o local 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 eu gostaria de evitar essa rota, se possível.

Obrigado!

EDIT: A linha de comando real que a primeira instância usa para iniciar as instâncias adicionais é semelhante a start cmd /C "call my_program.exe > output_1.txt" . Então eu passar 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?

    
por BimmerM3 13.10.2015 / 20:20

2 respostas

1

Após alguns breves testes, eu diria que sua suposição parece estar correta. Se você quiser confirmar isso, recomendo Processar Hacker . (Há um botão "Downloads" no topo; tenha cuidado, pois os anúncios estão mostrando links de download inválidos.) Hacker, Encontrar Identificadores ou DLLs ... (Ctrl-F)

Com 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.

Note que pode ser melhor escrever para um nome de arquivo único ... considere isto: ao invés de output_1.txt a primeira sub-chamada, e output_2.txt a segunda sub-chamada, verifique quais arquivos preexistem. Em seguida, vá mais alto, para que você não acabe sobrescrevendo um arquivo ou encontrando problemas porque não pode anexá-lo porque o arquivo está em uso. Sistemas operacionais e linguagens de programação frequentemente fornecem funcionalidade para gerar um nome de arquivo exclusivo.

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

Se você tiver o código-fonte para program.exe, em vez de executar "program.exe > filename", basta usar "program.exe filename". Coloque o código em seu programa para gravar o arquivo rapidamente e, em seguida, 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é mesmo executar algum "bloqueio" ... 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 customizada que só chama printf () se não houver 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ê alterar o arquivo de saída, basta 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 levar mais tempo. No entanto, eu vou deixar você saber que eu, pessoalmente, me economizei muito tempo e esforço depois que eu encontrei essa abordagem. Eu vejo isso como uma boa solução a longo prazo.

Ou considere o uso da funcionalidade de registro em log do sistema operacional. Isto pode ser feito executando um comando a partir da linha de comando: No Unix, execute o "logger"; no MS Windows, execute EventCreate . Deveria haver maneiras de fazer isso diretamente da sua escolha de linguagem de programação (MSDN C, como você observou). Isso pode ser útil se a saída for demorada ou se você estiver preocupado com a sobrecarga dos logs do sistema operacional. (Eu sei que alguns lugares têm monitoramento ativo de logs do sistema operacional.)

    
por 14.10.2015 / 08:49
0

É uma suposição razoável.

1) Por favor, 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 está 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?

    
por 13.10.2015 / 21:23