Freeze ao iniciar programaticamente um arquivo em lotes (com redirecionamento de saída), quando o arquivo em lotes simplesmente chama “start some.exe”

EDIT: Foram encontradas algumas duplicatas sem respostas:

Problema com redirecionamento de saída no loteComo uso o comando "start" sem herdar identificadores no processo filh

Tenho um código C # que tenta ser um iniciador de processos genérico, dentro de um programa maior de longa duração. Esse código precisa capturar a saída dos processos que inicia e também esperar que eles terminem. Normalmente, iniciamos arquivos em lote com esse código e tudo funciona bem, exceto quando queremos iniciar outro processo filho de dentro do arquivo em lotes, para que ele sobreviva ao processo de arquivos em lote. Como exemplo, digamos que eu simplesmente queira executar "start notepad.exe "de dentro do arquivo em lotes.

Encontrei os mesmos problemas que nesta pergunta: Process.WaitForExit não retorna, embora Process.HasExited seja true

Basicamente, mesmo que o processo do arquivo em lotes pareça estar saindo muito rapidamente (conforme o esperado), meu programa congela até que o processo filho (por exemplo, o bloco de notas) também saia. No entanto, o bloco de notas não deve sair, no meu cenári

Tentei injetar "cmd.exe / C" em todos os pontos da cadeia, sem sorte. Tentei terminar explicitamente o arquivo em lotes com "exit" ou "exit / B". Tentei ler a saída de forma síncrona e assíncrona - com ou sem threads de trabalho. Eu tentei os padrões aqui:https: //github.com/alabax/CsharpRedirectStandardOutput/tree/master/RedirectStandardOutputLibrar (consulte FixedSimplePattern.cs e AdvancedPattern.cs), novamente sem sort

EDIT: Eu também tentei com algum código C # P / Invoke que executa o processo através da API do Windows (CreatePipe / CreateProcess, etc), por isso não acho que esse problema seja específico da API de processo do C #.

A única solução alternativa encontrada foi a substituição do comando start por uma ferramenta que chama CreateProcess pelo sinalizador DETACHED_PROCESS (CREATE_NO_WINDOW também funciona

A resposta aceita na pergunta SO mencionada https: //stackoverflow.com/a/26722542/593200) é a coisa mais próxima em toda a Internet que parece funcionar, mas acontece que há vazamentos de tópicos em todos os arquivos em lotes iniciados. Eu teria deixado um comentário lá, mas ainda não tenho reputação de fazer isso:).

Código modificado que demonstra vazamento de thread:

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace TestSO26713374WaitForExit
{
    class Program
    {
    static void Main(string[] args)
    {
        while(true)
        {
            string foobat =
@"@echo off
START ping -t localhost
REM START ping -t google.com
REM ECHO Batch file is done!
EXIT /B 123
";

            File.WriteAllText("foo.bat", foobat);

            Process p = new Process
            {
                StartInfo =
                new ProcessStartInfo("foo.bat")
                {
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                }
            };

            p.Start();

            var _ = ConsumeReader(p.StandardOutput);
            _ = ConsumeReader(p.StandardError);

            //Console.WriteLine("Calling WaitForExit()...");
            p.WaitForExit();
            //Console.WriteLine("Process has exited. Exit code: {0}", p.ExitCode);
            //Console.WriteLine("WaitForExit returned.");


            ThreadPool.GetMaxThreads(out int max, out int max2);
            ThreadPool.GetAvailableThreads(out int available, out int available2);

            Console.WriteLine(
                $"Active thread count: {max - available} (thre,ad pool), {System.Diagnostics.Process.GetCurrentProcess().Threads.Count} (all).");

            Thread.Sleep(8000);
        }
    }

    async static Task ConsumeReader(TextReader reader)
    {
        string text;

        while ((text = await reader.ReadLineAsync()) != null)
        {
            Console.WriteLine(text);
        }
    }
}
}

A saída acima:

Active thread count: 2 (thread pool), 15 (all).
Active thread count: 4 (thread pool), 18 (all).
Active thread count: 6 (thread pool), 19 (all).
Active thread count: 8 (thread pool), 20 (all).
Active thread count: 9 (thread pool), 21 (all).
Active thread count: 11 (thread pool), 23 (all).
Active thread count: 13 (thread pool), 25 (all).
Active thread count: 15 (thread pool), 27 (all).
Active thread count: 17 (thread pool), 29 (all).
Active thread count: 19 (thread pool), 31 (all).
Active thread count: 21 (thread pool), 33 (all).
...

Minhas perguntas

Por que o comando start não quebra completamente a cadeia de redirecionamento de saíd Estou preso à ferramenta mencionada acima que chama CreateProcess (... DETACHED_PROCESS ...)?

Obrigado

questionAnswers(2)

yourAnswerToTheQuestion