.NET Process.Start로 실행할 때 프로세스 중단 — 무엇이 문제입니까?

StackOverflow https://stackoverflow.com/questions/439617

  •  22-07-2019
  •  | 
  •  

문제

일부 콘텐츠를 검색하고 이를 사용하여 작업을 수행하기 위해 svn.exe 주위에 빠르고 지저분한 래퍼를 작성했지만 특정 입력의 경우 가끔 재현 가능하게 멈추고 완료되지 않습니다.예를 들어, svn list에 대한 호출은 다음과 같습니다.

svn list "http://myserver:84/svn/Documents/Instruments/" --xml  --no-auth-cache --username myuser --password mypassword

이 명령줄은 명령 셸에서 실행하면 제대로 실행되지만 앱에서는 작동이 멈춥니다.이것을 실행하는 내 C# 코드는 다음과 같습니다.

string cmd = "svn.exe";
string arguments = "list \"http://myserver:84/svn/Documents/Instruments/\" --xml  --no-auth-cache --username myuser --password mypassword";
int ms = 5000;
ProcessStartInfo psi = new ProcessStartInfo(cmd);
psi.Arguments = arguments;
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
StreamReader output = new StreamReader(proc.StandardOutput.BaseStream, Encoding.UTF8);

proc.WaitForExit(ms);
if (proc.HasExited)
{
    return output.ReadToEnd();
}

이 작업은 전체 5000ms가 소요되며 완료되지 않습니다.시간을 연장하는 것은 도움이 되지 않습니다.별도의 명령 프롬프트에서는 즉시 실행되므로 대기 시간이 부족한 것과는 관련이 없다고 확신합니다.그러나 다른 입력의 경우에는 정상적으로 작동하는 것 같습니다.

또한 여기에서 별도의 cmd.exe를 실행해 보았지만(exe는 svn.exe이고 args는 원래 인수 문자열임) 여전히 중단이 발생했습니다.

string cmd = "cmd";
string arguments = "/S /C \"" + exe + " " + args + "\"";

여기서 무엇을 망칠 수 있으며, 이 외부 프로세스를 어떻게 디버깅할 수 있습니까?

편집하다:

나는 지금 막 이 문제를 다루려고 노력하고 있습니다.실제로 훌륭하게 작동하는 그의 제안에 대해 Jon Skeet에게 감사드립니다.하지만 저는 멀티스레드 초보자이기 때문에 이것을 처리하는 방법에 대해 또 다른 질문이 있습니다.눈에 띄는 결함이나 기타 멍청한 점을 개선하는 방법에 대한 제안을 받고 싶습니다.결국 stdout 스트림, 출력을 보관할 StringBuilder, 완료 시점을 알려주는 플래그가 포함된 작은 클래스를 만들었습니다.그런 다음 ThreadPool.QueueUserWorkItem을 사용하고 내 클래스의 인스턴스를 전달했습니다.

ProcessBufferHandler bufferHandler = new ProcessBufferHandler(proc.StandardOutput.BaseStream,
                                                                          Encoding.UTF8);
ThreadPool.QueueUserWorkItem(ProcessStream, bufferHandler);

proc.WaitForExit(ms);
if (proc.HasExited)
{
    bufferHandler.Stop();
    return bufferHandler.ReadToEnd();
}

...그리고 ...

private class ProcessBufferHandler
{
    public Stream stream;
    public StringBuilder sb;
    public Encoding encoding;
    public State state;

    public enum State
    {
        Running,
        Stopped
    }

    public ProcessBufferHandler(Stream stream, Encoding encoding)
    {
        this.stream = stream;
        this.sb = new StringBuilder();
        this.encoding = encoding;
        state = State.Running;
    }
    public void ProcessBuffer()
    {
        sb.Append(new StreamReader(stream, encoding).ReadToEnd());
    }

    public string ReadToEnd()
    {
        return sb.ToString();
    }

    public void Stop()
    {
        state = State.Stopped;
    }
}

이것이 효과가 있는 것 같지만 이것이 최선의 방법인지는 의심스럽습니다.이것이 합리적인가?그리고 이를 개선하려면 어떻게 해야 합니까?

도움이 되었습니까?

해결책

한 가지 표준 문제:프로세스는 사용자가 출력을 읽기를 기다리고 있을 수 있습니다.종료를 기다리는 동안 표준 출력에서 ​​읽을 별도의 스레드를 만듭니다.약간 고통스럽기는 하지만 그게 문제일 수도 있습니다.

다른 팁

Jon Skeet은 돈에 맞습니다!

SVN 명령을 시작한 후 폴링이 마음에 들지 않으면 다음을 시도하십시오.

Process command = new Process();
command.EnableRaisingEvents = false;
command.StartInfo.FileName = "svn.exe";
command.StartInfo.Arguments = "your svn arguments here";
command.StartInfo.UseShellExecute = false;
command.StartInfo.RedirectStandardOutput = true;
command.Start();

while (!command.StandardOutput.EndOfStream)
{
    Console.WriteLine(command.StandardOutput.ReadLine());
}

클라이언트의 컴퓨터에 EXE를 떨어 뜨려 프로세스를 사용하여 시작하여 시작해야했습니다.

호출 응용 프로그램이 중단 될 것입니다. 문제는 EXE가 위험하다고 가정하고 다른 응용 프로그램이 시작되는 것을 방지하는 데 기계가되었습니다.

EXE를 마우스 오른쪽 버튼으로 클릭하고 속성으로 이동하십시오. 보안 경고 옆 바닥을 향해 "차단 해제"를 누르십시오.

enter image description here

나는 이것이 오래된 게시물이라는 것을 알고 있지만 아마도 이것은 누군가를 도울 것입니다. 나는 이것을 사용하여 AWS를 실행했습니다 (아마존 웹 서비스) .NET TPL 작업을 사용하는 CLI 명령.

내 명령 실행에서 이와 같은 일을 했는 bgwRun_DoWork 루프를 고정하는 방법 while(!bgwRun.CancellationPending). 여기에는 .NET ThreadPool 클래스를 사용하여 새 스레드를 통해 프로세스에서 표준 출력을 읽는 것이 포함됩니다.

private void bgwRun_DoWork(object sender, DoWorkEventArgs e)
{
  while (!bgwRun.CancellationPending)
  {
   //build TPL Tasks
   var tasks = new List<Task>();

   //work to add tasks here

   tasks.Add(new Task(()=>{

     //build .Net ProcessInfo, Process and start Process here

     ThreadPool.QueueUserWorkItem(state =>
       {
           while (!process.StandardOutput.EndOfStream)
           {
               var output = process.StandardOutput.ReadLine();
               if (!string.IsNullOrEmpty(output))
               {
                   bgwRun_ProgressChanged(this, new ProgressChangedEventArgs(0, new ExecutionInfo
                   {
                       Type = "ExecutionInfo",
                       Text = output,
                       Configuration = s3SyncConfiguration
                   }));
               }

               if (cancellationToken.GetValueOrDefault().IsCancellationRequested)
               {
                     break;
               }
           }
       });
   });//work Task

   //loop through and start tasks here and handle completed tasks

  } //end while
}

내 SVN 저장소가 때때로 느리게 실행될 수 있다는 것을 알고 있으므로 5 초가 길지 않습니까? 브레이크 포인트에서 프로세스에 전달하는 문자열을 복사 했으므로 긍정적 인 것이 긍정적이지 않습니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top