Я написал упрощенную версию моей программы ниже. Процесс 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();
}
Спасибо за ваши предложения. Я обновил свой код, чтобы отразить их. Я по-прежнему сохранял проверку pipeServer.IsConnected в цикле while, чтобы избежать исключения большинства исключений. Я также добавил чек, чтобы убедиться, что процесс все еще реагирует. – user2481095
Это сломано двумя способами: _Process.Responding - это графический интерфейс, поэтому, вероятно, это не так. И даже если вы хотите эту семантику, вы можете отбросить буферизованные данные, если процесс перестает отвечать на запросы. Во-вторых, даже если pipeServer.IsConnected становится ложным, потоковод может иметь данные, буферизованные, которые вы потеряете. 'if (temp == null) continue;' this должно быть '... break ;'. Вы почти никогда не увидите исключения, потому что большую часть времени удаленный дескриптор будет закрыт, и вы получите нуль. – usr
'_Process.Kill(); return; 'нуждается в WaitForExit, потому что убийство не мгновенно. МО могут задержаться. Кроме того, вы не должны убивать процесс только потому, что он закрыл свою трубу. Он все еще может делать что-то и закрывать. Может быть, только убить, после того, как WaitForExit вернет false? – usr