Зависание процесса при запуске с помощью .NET Process.Start — что не так?

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

  •  22-07-2019
  •  | 
  •  

Вопрос

Я написал быструю и грязную обертку для 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 — исходная строка аргумента), но зависание все равно произошло:

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

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

РЕДАКТИРОВАТЬ:

Я только сейчас собираюсь заняться этим вопросом.Мучо благодарит Джона Скита за его предложение, которое действительно отлично работает.Однако у меня есть еще один вопрос о моем методе решения этой проблемы, поскольку я новичок в многопоточной работе.Я хотел бы получить предложения по улучшению любых вопиющих недостатков или чего-то еще глупого.В итоге я создал небольшой класс, содержащий поток 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;
    }
}

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

Это было полезно?

Решение

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

Другие советы

Джон Скит прав в вопросе денег!

Если вы не против опроса после запуска команды 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-файл на клиентскую машину и использовать Process.Start для его запуска.

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

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

enter image description here

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

Я сделал что-то подобное при выполнении своей команды, которая выполняется в задаче .Net TPL, созданной в моем фоновом работнике WinForm. 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