C#读取重定向标准输入的难题

最近因为测试taskBus技术,需要在进程中重定向子进程(c#开发)的标准输入(stdin)。这样,C#子进程中直接可以Console.Read出主进程给的数据。

由于前期在C++、Python2/3、Node.JS等语言上均实现了子进程,而且非常简单,所以也就没当回事儿。没想到,CSharp实现起来却是困难重重!这里特此记录:

  • 如果主进程启动子进程后,没有向C#子进程的stdin写入任何东西,而是把stdin放在那里不管,则会导致子进程停在 Read()函数里一直等待。
  • 一旦进入上述等待状态,即使后续写入数据,也无法恢复。

这个问题超级诡异,我认为是.Net的BUG(4.6)。我在一个老外的博客里找到了几乎一样的遭遇:

https://daveaglick.com/posts/capturing-standard-input-in-csharp

最终借鉴Dave的代码,实现了读取字节的函数:

public byte[] read_from_stdin(int size)
{
    byte[] buffer = new byte[size];
    int red = 0;
    System.IO.Stream stream = Console.OpenStandardInput();
    int read = -1;
    AutoResetEvent gotInput = new AutoResetEvent(false);
    while (read< size)
    {
        Thread inputThread = new Thread(() =>
        {
            try
            {
                read = stream.Read(buffer, red, buffer.Length - red);
                red += read;
                gotInput.Set();
            }
            catch (ThreadAbortException)
            {
                Thread.ResetAbort();
            }
        })
        {
            IsBackground = true
        };
        inputThread.Start();
        // Timeout expired?
        if (!gotInput.WaitOne(100))
            inputThread.Abort();                    
    }
    return buffer;
}

主要的替代解决(很不优雅)是采用一个线程读取,一个线程监视,不管成不成功,100毫秒后都强制杀死读取线程。相关工程文件见

https://github.com/goldenhawking/taskBus/blob/master/module_templates/csharp/Program.cs

你可能感兴趣的:(开源,架构)