5

我試圖用C#來控制命令行應用程序的背景,這可以在這裏下載進度:http://www.ti.com/litv/zip/spmc015b異常異步讀操作的已經在上StandardOutput流

這是電動機電壓的應用控制,當我進入應用程序,如「b.exe -c 1」,控制檯似乎是一種阻塞模型。此應用程序中的每個命令都以「#」符號開頭。見圖片瀏覽:

http://i46.tinypic.com/zx5edv.jpg

我想要做的是,用StandardInput.WriteLine( 「STAT VOUT」);測量電壓。這將向控制檯背景發送一個「stat vout」命令,並理想地返回一個電壓值。在這張照片中,它會返回一些幫助提示。 Duing這一次,它仍然處於阻塞模式。

我想與StandardOutput.ReadLine返回消息();但失敗了。如果ReadToEnd()那麼我的程序被凍結,因爲這個應用程序永遠不會返回到阻塞的標準控制檯。

當我試圖BeginOutputReadLine(); OutputDataReceived事件可以真正從控制檯獲得消息返回,如在「stat [vout | vbus | fault」的圖片中。但它限制在我的單線程中。

我現在的情況是,我使用System.Timers.Timers在WinForms和每一秒就會發出「STAT VOUT2」命令來讀取電壓,並希望得到返回值。

但是,System.Timers.Timers是異步的,所以當我在此定時器線程中調用BeginOutputReadLine()時,它提示「異步讀操作已在流上啓動」。同時,正如我上面演示的那樣,我不能使用像ReadLine()這樣的同步方法來獲取值。

那麼應該怎麼辦?我真的需要在多線程模式下運行這個命令行應用程序。

非常感謝,祝大家有一個愉快的週末。上04月28日19時18分CST

--update下面是相關的源代碼:

其中WinFroms按鈕將啓動()的SystemClock類,然後Timing.Measuring()被執行每一秒。根據SystemClock,TimingController類將在一秒鐘內同時調用GetVoltage()和GetCurrent(),以測量電壓和電流。

在測量類中,StandardInput.WriteLine(「stat vout2」);從控制檯應用程序獲取電壓,以及StandardInput.WriteLine(「stat cur」);獲取最新資訊。他們都使用BeginOutputReadLine()來獲得結果,因爲StandardOutput不起作用。

我用isOutputObtained標誌與表示,如果返回的數據。每次閱讀完成後,我確實調用了CancelOutputRead();取消異步讀取。

但它仍然給我的「異步讀操作已在StandardOutput流進步」

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(); 
     } 
    } 
} 
+0

發佈一些相關的代碼可能會有所幫助。 – 2012-04-28 09:29:04

+0

我的代碼太長,我會將其作爲新答案顯示 – Asker 2012-04-28 22:10:52

+1

不,這不是一個答案。把它放在問題上。 – 2012-04-28 22:33:04

回答

0

錯誤例外,我認爲你有兩個選擇。

如果是可以的,因爲前一個時間太長,會錯過一個樣品,然後設置一個標誌,表明您已經提供樣品。

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

    bool isMeasuring = false; 

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

    private void Measuring() 
    { 
     if(isMeasuring) return; 

     isMeasuring = true; 
     CurrentVoltage = Measure.GetVoltage(); 
     CurrentCurrent = Measure.GetCurrent(); 
     isMeasuring = false; 
    } 
} 

如果不能確定會錯過的區間,你可以嘗試創建爲每個調用一個新的工藝對象,而不是重用現有的過程。儘管這些命令需要很長時間才能完成,但這可能會創造出很多孩子。