none
急!An asynchronous read operation is already in progress on the StandardOutput stream RRS feed

  • 问题

  • 大家好,有个很棘手的问题

    我正在用C#后台控制一个命令行程序,可以从这儿下载到:http://www.ti.com/litv/zip/spmc015b

    这是一个用于控制电压的命令行,当我进入该程序后,如图 输入 "b.exe -c 1",该命令行就出于阻塞模式下,每一行命令都有 提示符# 开头,而不会返回标准控制台

    我需要做的是,在 #之后由 StandardInput.WriteLine("stat vout")来输入测量命令,该控制台应该会返回如图所示的结果,并继续出于阻塞状态,#提示符等待下一条命令

    如果用一句 StandardOutput.ReadLine,则什么都读不到,如果用 ReadToEnd 则程序卡住,因为要等待标准输出流,而实际上这是一个阻塞式的命令行程序,所以 StandardOutput 失败了。

    当我尝试用 BeginOutputReadLine 的时候,OutputDataReceived 事件中的确能获取到图示的 stat [vout|vbus|fault 等字符,哪怕是阻塞式,但是这仅限于单线程模式。

    我现在的情况是,在 winform 下,System.Timers.Timers 间隔一秒钟发送一条读取数据命令

    该命令行启动后,由 System.Timers.Timers(异步多线程) 间隔一定时间用 StandardInput 发送一条读取数据命令 stat,希望得到该命令的返回数据。但是,由于 System.Timers.Timers 是异步的(我的情况不能用 winform 的定时器,只能用异步定时器),所以在这个 Timers 线程中调用 BeginOutputReadLine 方法读取数据的时候,出现异常,提示 An async read operation has already been started on the stream.

    请问有什么好的方法解决这个问题么?我确实需要在异步下执行读取数据,而同步方式的 StandardOutput.Readline 又无法读取到阻塞式命令行

    2012年4月28日 8:22

答案

全部回复

  • 这是相关部分的源代码:

    WinFroms 中的某个按钮启动 SystemClock类 中的Start() ,然后 Timing.Measuring() 每隔一秒执行一次去测量电压电流。GetVoltage() 和 GetCurrent() 就是用来获取测量数据的函数。

    在 Measuring类中, StandardInput.WriteLine("stat vout2"); 用来给那个后台命令行程序发送一条读取电压的命令,StandardInput.WriteLine("stat cur") 读取电流。同时他们用 BeginOutputReadLine() 方法来返回异步读取结果,因为 StandardOutput 无效,上面说过了

    isOutputObtained 是一个标志用来确定是否已经触发了OutputDataReceived事件了。每次触发结束,我都调用 CancelOutputRead()来取消异步读取的。

    看起来应该没啥问题,但为何还是在第一次测量的时候就提示 "An asynchronous read operation is already in progress on the StandardOutput stream"???

        public class SystemClock
        {
            TimingController Timing = new TimingController();
            private Timer TimerSystemClock;

            public SystemClock()
            {
                TimerSystemClock = new Timer();
                TimerSystemClock.Interval = 1000;
                TimerSystemClock.AutoReset = true;
                TimerSystemClock.Elapsed += new ElapsedEventHandler(TimerSystemClock_Elapsed);
                TimerSystemClock.Enabled = false;
                Timing.ClockInstance = this;
            }

            public void Start()
            {
                TimerSystemClock.Enabled = true;
            }

            void TimerSystemClock_Elapsed(object sender, ElapsedEventArgs e)
            {
                Timing.Measuring();
            }
        }

        public class TimingController
        {
            // Get singleton of Measurement Class
            Measurement Measure = Measurement.GetInstance();       

            public SystemClock ClockInstance
            {
                get { return Clock; }
                set { Clock = value; }
            }

            private void Measuring()
            {
                CurrentVoltage = Measure.GetVoltage();
                CurrentCurrent = Measure.GetCurrent();
            }
        }

        public sealed class Measurement
        {
            // Singleton
            public static readonly Measurement instance = new Measurement();
            public static Measurement GetInstance()
            {
                return instance;
            }

            private Process ProcMeasuring = new Process();
            double measureValue
            bool isOutputObtained;

            private Measurement()
            {
                ProcMeasuring.StartInfo.FileName = "b.exe";
                ProcMeasuring.StartInfo.Arguments = "-c 1";
                ProcMeasuring.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
                ProcMeasuring.StartInfo.UseShellExecute = false;
                ProcMeasuring.StartInfo.RedirectStandardInput = true;
                ProcMeasuring.StartInfo.RedirectStandardOutput = true;
                ProcMeasuring.StartInfo.RedirectStandardError = true;
                ProcMeasuring.StartInfo.CreateNoWindow = true;
                ProcMeasuring.OutputDataReceived += new DataReceivedEventHandler(MeasurementOutputHandler);
            }

            public double GetVoltage(Machine machine)
            {
                isOutputObtained = false;

                ProcMeasuring.StandardInput.WriteLine("stat vout2");
                ProcMeasuring.BeginOutputReadLine();

                while (!isOutputObtained)
                {
                    isOutputObtained = true;
                }

                return measureValue;
            }

            public double GetCurrent(Machine machine)
            {
                isOutputObtained = false;

                ProcMeasuring.StandardInput.WriteLine("stat cur");
                ProcMeasuring.BeginOutputReadLine();

                while (!isOutputObtained)
                {
                    isOutputObtained = true;
                }

                return measureValue;
            }

            private void MeasurementOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
            {
                if (!String.IsNullOrEmpty(outLine.Data) && (outLine.Data != "# "))
                {                
                    measureCurrentValue = Convert.ToDouble(outLine.Data);
                    isOutputObtained = true;

                    ProcMeasuring.CancelOutputRead();
                }
            }
        }

                                   

    2012年4月28日 22:14
  • 2012年5月2日 3:08