Подтвердить что ты не робот

Висячий процесс при запуске с .NET Process.Start - что не так?

Я написал быстрый и грязный обертку вокруг svn.exe, чтобы получить некоторый контент и что-то сделать с ним, но для некоторых входов он иногда и воспроизводимо зависает и не заканчивается. Например, одним вызовом является список svn:

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

Эта командная строка отлично работает, когда я просто делаю это из командной оболочки, но она зависает в моем приложении. Мой код С# для запуска:

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();
}

Это занимает 5000 мс и никогда не заканчивается. Продление времени не помогает. В отдельной командной строке он запускается мгновенно, поэтому я уверен, что он не связан с недостаточным временем ожидания. Однако для других входов это работает нормально.

Я также попробовал запустить отдельный cmd.exe здесь (где exe - svn.exe, а args - исходная строка arg), но повесился все еще:

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

Что я могу здесь прикрутить, и как я могу отлаживать этот внешний процесс?

EDIT:

Я только сейчас обойдусь этим. Mucho благодаря 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;
    }
}

Это похоже на работу, но я сомневаюсь, что это лучший способ. Это разумно? И что я могу сделать, чтобы улучшить его?

4b9b3361

Ответ 1

Один стандартный вопрос: процесс может ждать, пока вы его прочитаете. Создайте отдельный поток, чтобы читать его стандартный вывод, пока вы ждете его выхода. Это немного боль, но это может быть проблемой.

Ответ 2

Джон Скит прямо на деньги!

Если вы не возражаете против опроса после запуска команды 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());
}

Ответ 3

Я знаю, что мои SVN-репозиции могут работать медленно, поэтому, возможно, 5 секунд недостаточно долго? Вы скопировали строку, которую вы передаете процессу из точки останова, поэтому вы уверены, что ничего не подсказывает?

Ответ 4

Я знаю, что это старый пост, но, возможно, это поможет кому-то. Я использовал это для выполнения некоторых команд CLI AWS (Amazon Web Services) с использованием задач .Net TPL.

Я сделал что-то подобное в моем исполнении команды, которая выполняется в задаче .NET TPL, которая создается в моем методе background рабочего bgwRun_DoWork для WinForm, который содержит цикл с 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
}

Ответ 5

Мне пришлось отказаться от exe на клиентской машине и использовать Process.Start для ее запуска.

Вызывающее приложение будет зависать после вызова, и проблема закончилась тем, что их машина предположила, что exe опасна и не позволяет другим приложениям запускать ее.

Щелкните правой кнопкой мыши exe и перейдите к свойствам. Нажмите "Разблокировать" в нижней части экрана рядом с предупреждением безопасности.

enter image description here