2016-01-22 85 views
0

我在下面編寫了我的程序的簡化版本。進程A啓動一個子進程(進程B)。我使用匿名管道來寫入有關在進程B上運行的方法進度的信息。同時,我在進程A中有一個函數,它不斷從流中讀取數據,以查看是否有來自管道的新更新。如果存在,則更新流程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條件沒有必要。只需閱讀,直到temp爲空。這是流的最終信號。

設置爲while(true)循環。

我想你還需要添加異常處理來捕獲進程終止和切斷管道。 !_Process.HasExited && pipeServer.IsConnected是不夠的,因爲它可能是真的,但在測試後立即切換爲假。

我還會在最後添加一個WaitForExit以確保系統在繼續之前處於停頓狀態。

+0

感謝您的建議。我更新了我的代碼以反映它們。我仍然在while循環中保留pipeServer.IsConnected檢查,以避免拋出大多數異常。我還添加了一個檢查以確保該流程仍然響應。 – user2481095

+0

這在兩種方式中被破壞:_Process.Responding是基於GUI的,所以可能不正確。即使您需要這些語義,如果進程無響應,您也可能會丟棄緩衝的數據。其次,即使pipeServer.IsConnected變爲false,流式讀取器可能會緩衝數據,導致丟失數據。 'if(temp == null)continue;'this should be'... break;'。您幾乎從不會在這裏看到異常,因爲大部分時間遠程句柄將被關閉,您將收到空值。 – usr

+0

'_Process.Kill(); return;'需要WaitForExit很好,因爲查殺不是即時的。 IO可能會徘徊。另外,你不應該因爲關閉管道而殺死進程。它可能仍在做着事情並關閉。也許只有在WaitForExit返回false後才能殺死? – usr