写入Process.StandardInput时发生死锁

本文关键字:死锁 Process StandardInput 写入 | 更新日期: 2023-09-27 18:26:33

我正在开发一个应用程序,遇到死锁问题。

我的代码是这样的:

Process p = new Process(); // That using an other application

然后我将向这个进程发送一个.xml文件:

XmlSerializer xs = new XmlSerializer(data.GetType());
using (var ms = new MemoryStream())
{
    var sw = new StreamWriter(ms);
    XmlWriter xmlwriter = XmlWriter.Create(sw, xmlWriterSettings);
    xmlwriter.WriteProcessingInstruction("PipeConfiguratorStyleSheet", processing);
    xs.Serialize(xmlwriter, data);
    xmlwriter.Flush();
    ms.Position = 0;
    var sr = new StreamReader(ms);
    while (!sr.EndOfStream)
    {
        String line = sr.ReadLine();
        p.StandardInput.WriteLine(line);                
        Console.WriteLine(line);
        p.BeginOutputReadLine();
        p.CancelOutputRead(); 
    }
}

因此,实际上我可以将.xml文件的一部分发送到我的进程,但在某个时刻我会遇到死锁。我想我不知道如何正确使用BeginOutputReadLine()

写入Process.StandardInput时发生死锁

首先,为什么不像一样直接使用Process.StandardInput-属性作为目标

var process = new Process
{
    // all your init stuff
};
var xmlSerializer = new XmlSerializer(data.GetType());
var xmlwriter = XmlWriter.Create(process.StandardInput, xmlWriterSettings);
xmlSerializer.Serialize(xmlwriter, data);

否则,msdn条目提供了使用Process.BeginOutputReadLine()的明确方法,您可以将其重新构造为

var autoResetEvent = new AutoResetEvent(false); // this mutex acts as our bouncer for the reading-part
var process = new Process
{
    // all your init stuff
};
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, args) => {
    // TODO you could read the content here with args.Data
    autoResetEvent.Set();
};
process.Start();
using (var memoryStream = new MemoryStream())
{
    using (var streamWriter = new StreamWriter(memoryStream))
    {
        var xmlSerializer = new XmlSerializer(data.GetType());
        var xmlwriter = XmlWriter.Create(streamWriter, xmlWriterSettings);
        xmlSerializer.Serialize(xmlwriter, data);
    }
    memoryStream.Position = 0;
    using (var streamReader = new StreamReader(memoryStream))
    {
        while (!streamReader.EndOfStream)
        {
            var line = streamReader.ReadLine();
            process.StandardInput.WriteLine(line);
            Console.WriteLine(line);
            process.BeginOutputReadLine();
            autoResetEvent.WaitOne();
        }
    }
}
// TODO closing the process.StandardInput, exiting process, ...

不管怎样——我知道这应该是一条评论——你等待你的流程写东西有什么具体的原因吗?

StandardOutput流可以同步读取,也可以异步读取。Read、ReadLine和ReadToEnd等方法执行同步读取对进程输出流的操作。这些同步读取直到关联的进程写入其StandardOutput流,或关闭流。相反BeginOutputReadLine在StandardOutput流。此方法启用指定的事件处理程序对于流输出,并立即返回给调用者,调用者可以在流输出指向事件时执行其他工作处理程序。

这意味着,如果您的进程没有写入任何内容(并且您正在等待),那么您将无休止地等待响应。。。

编辑

您还应该像一样向Process.ErrorDataReceived添加一个处理程序

process.StartInfo.RedirectStandardError = true;
process.ErrorDataReceived += (sender, args) => {
    // TODO do something with the response of args.Data
    autoResetEvent.Set();
};

while (!streamReader.EndOfStream)
{
    var line = streamReader.ReadLine();
    process.StandardInput.WriteLine(line);
    Console.WriteLine(line);
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    autoResetEvent.WaitOne();
}

以处理错误情况(无论这可能意味着什么)。