2016-01-22 4 views
0

Я написал упрощенную версию моей программы ниже. Процесс A запускает дочерний процесс (процесс B). Я использую анонимный канал для записи информации о ходе метода, запущенного в процессе B. Между тем у меня есть функция в процессе A, которая постоянно читает из потока, чтобы узнать, есть ли новое обновление, поступающее из канала. Если есть, форма в процессе А обновляется, чтобы отразить прогресс. Это работает так, как ожидалось, однако мне интересно, есть ли лучший способ достичь этого, не требуя постоянного проверки потока, чтобы узнать, есть ли какие-либо новые обновления прогресса.Как эффективно читать из потока труб при использовании IPC C#

///////////////// 
///Process A //// 
///////////////// 

public void LaunchProcessB() 
{ 
    using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In, 
      HandleInheritability.Inheritable)) 
    { 
     var _Process = new Process(); 
     _Process.StartInfo.FileName = exeString; 
     _Process.StartInfo.Arguments = pipeServer.GetClientHandleAsString() 
     _Process.StartInfo.RedirectStandardOutput = true; 
     _Process.StartInfo.RedirectStandardInput = true; 
     _Process.StartInfo.CreateNoWindow = true; 
     _Process.StartInfo.UseShellExecute = false; 
     _Process.Start(); //launches process B 

     pipeServer.DisposeLocalCopyOfClientHandle(); 

     using (StreamReader sr = new StreamReader(pipeServer)) 
     { 
      try 
      { 
       while (true) 
       { 
        string temp = sr.ReadLine(); 
        if (temp == null) break; 

        int result; 
        if (Int32.TryParse(temp, out result)) 
         ShowDocumentProgress(result); 
        else ShowProgress(temp); 
       } 
      } 
      catch (Exception) 
      { 
       //error occured when reading from stream. 
      } 
     } 

     if (!_Process.Responding && !_Process.HasExited) 
     { 
      _Process.Kill(); 
      return; 
     } 

     _Process.WaitForExit(10000); 
    } 
} 

private void ShowProgressPercent(int percentage) 
{ 
    if (percentage > currentPercentage) 
    { 
     progressBar.Value = percentage; 
    } 
} 

private void ShowProgress(string progressString) 
{ 
    labelMessage.Text = progressString; 
} 


///////////////// 
///Process B //// 
///////////////// 

private StreamWriter _progressWriter; 
private PipeStream _progressPipe; 

static int Main(string[] args) 
{ 
    using (progressPipe = new AnonymousPipeClientStream(PipeDirection.Out, args[0])) 
    using (_progressWriter = new StreamWriter(_progressPipe)) 
    { 
     RunLongProcess() 
    } 
} 

private void RunLongProcess() 
{ 
    //attaches events to PercentProgress and StageProgress methods. 
} 

private void PercentProgress(int percentage) 
{ 
    _progressWriter.WriteLine(percentage.ToString()); 
    _progressPipe.WaitForPipeDrain(); 
} 

private void StageProgress(string stage) 
{ 
    _progressWriter.WriteLine(stage); 
    _progressPipe.WaitForPipeDrain(); 
} 

ответ

2

В то время как условие не требуется. Просто прочитайте, пока темп не будет равен нулю. Это конечный сигнал потока.

Сделайте это while(true).

Я думаю, вам также необходимо добавить обработку исключений, чтобы уловить процесс, завершающий и отрывающий трубу. !_Process.HasExited && pipeServer.IsConnected недостаточно, потому что это может быть правдой, но сразу же переключиться на значение false после теста.

Я также хотел бы добавить WaitForExit в конец, чтобы убедиться, что система не работает до того, как вы продолжите.

+0

Спасибо за ваши предложения. Я обновил свой код, чтобы отразить их. Я по-прежнему сохранял проверку pipeServer.IsConnected в цикле while, чтобы избежать исключения большинства исключений. Я также добавил чек, чтобы убедиться, что процесс все еще реагирует. – user2481095

+0

Это сломано двумя способами: _Process.Responding - это графический интерфейс, поэтому, вероятно, это не так. И даже если вы хотите эту семантику, вы можете отбросить буферизованные данные, если процесс перестает отвечать на запросы. Во-вторых, даже если pipeServer.IsConnected становится ложным, потоковод может иметь данные, буферизованные, которые вы потеряете. 'if (temp == null) continue;' this должно быть '... break ;'. Вы почти никогда не увидите исключения, потому что большую часть времени удаленный дескриптор будет закрыт, и вы получите нуль. – usr

+0

'_Process.Kill(); return; 'нуждается в WaitForExit, потому что убийство не мгновенно. МО могут задержаться. Кроме того, вы не должны убивать процесс только потому, что он закрыл свою трубу. Он все еще может делать что-то и закрывать. Может быть, только убить, после того, как WaitForExit вернет false? – usr