用C#控制后台命令行程序输入输出该命令行启动后,由 System.Timers.Timers(异步多线程) 间隔一定时间发送一条读取数据命令,希望得到该命令的返回数据最早在winforms下做,将读取结果返回给winforms某个控件,于是用Process.BeginOutputReadLine成功得到了结果但现在由于应用需要在定时器线程下读取,在定时器线程中处理结果,而不需要异步返回读取结果,于是当我继续用原方法的时候,就出现了An async read operation has already been started on the stream.错误我又尝试 StandardOutput.ReadLine(),结果读不到值,因为我的命令行程序是如图所示的阻塞式的,不会返回控制台
该命令行启动后一直出于工作状态,直到程序退出。可以看到每个 #标记 作为一条命令的开始。
比如我输入 stat,返回了一串 “stat [vout|vbus|” 就是我要读取的数据,但是这个数据出现后不会返回控制台提示符但是在我现在的情况下,无论是BeginOutputReadLine还是StandardOutput都无法在主线程外的线程得到数据,请问有什么好的方法么?该命令行程序下载地址为: http://www.ti.com/litv/zip/spmc015b

解决方案 »

  1.   

    刚刚太急可能问题没描述清楚,我再缕一遍:
    我正在用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 又无法读取到阻塞式命令行
      

  2.   

    不懂,是不是跨线程??是了就INVOKE
      

  3.   

    INVOKE 可以,BeginOutputReadLine 这个异步方法当然是要 invoke 返回给UI主线程的的,我也在 winforms 上得到输出的数据了。但我现在的问题是,在 Timers 这个线程进程里,再调用 BeginOutputReadLine 这个异步方法就出标题的异常了  
      

  4.   

    这是相关部分的源代码:
    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();
                }
            }
        }