5

Sto cercando di utilizzare C# per controllare un'applicazione in background riga di comando, che può essere scaricato qui: http://www.ti.com/litv/zip/spmc015beccezione di un'operazione di lettura asincrona è già in corso sul torrente StandardOutput

Si tratta di un'applicazione per la tensione del motore controllo, quando inserisco l'app, come "b.exe -c 1", la console sembra una specie di modello di blocco. Ogni comando in questa app inizia con il simbolo "#". Vedi le foto qui:

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

Quello che sto cercando di fare è, utilizzare StandardInput.WriteLine ("stat Ua"); misurare la tensione. Ciò invierà un comando "stat vout" allo sfondo della console e restituirà idealmente un valore di tensione. In questa immagine, restituisce alcuni suggerimenti per l'aiuto. Duing per tutto questo tempo, è ancora in modalità di blocco.

Voglio ottenere il messaggio di ritorno con StandardOutput.ReadLine(); ma fallito. Se ReadToEnd() allora il mio programma è bloccato perché questa app non ritorna mai alla console standard, che sta bloccando.

Quando ho provato BeginOutputReadLine(); L'evento OutputDataReceived può veramente ottenere il ritorno del messaggio dalla console, come nelle immagini di "stat [vout | vbus | fault". Ma è limitato nel mio programma a thread singolo.

La mia situazione attuale è che, utilizzo System.Timers.Timers in WinForms e ogni secondo invierà un comando "stat vout2" per leggere la tensione, e si spera che ottenga il valore restituito.

Tuttavia, System.Timers.Timers è asincrono, quindi quando ho chiamato BeginOutputReadLine() in questo thread Timers, è stato richiesto "Un'operazione di lettura asincrona è già stata avviata nello stream". Nel frattempo, come ho dimostrato sopra, non posso usare metodi sincroni come ReadLine() per ottenere il valore.

Quindi cosa dovrei fare ora? Ho davvero bisogno di eseguire questa applicazione da riga di comando in modalità multi-threading.

Grazie mille e auguro a tutti un bel fine settimana.

--update il 28 apr 19:18 CST Ecco il codice sorgente di rilevante:

Uno dei WinFroms pulsante Start() la Classe SystemClock, quindi Timing.Measuring() viene eseguito ogni secondo. La classe TimingController chiamerà GetVoltage() e GetCurrent() allo stesso tempo durante un secondo secondo il SystemClock, per misurare la tensione e la corrente.

Nella classe di misurazione, StandardInput.WriteLine ("stat vout2"); per ottenere la tensione dall'app della console e StandardInput.WriteLine ("stat cur"); per ottenere la corrente. Entrambi utilizzano BeginOutputReadLine() per ottenere risultati poiché StandardOutput non ha funzionato.

Uso un flag isOutputObtained per indicare se i dati sono stati restituiti. Ogni volta che la lettura è finita, ho chiamato CancelOutputRead(); per cancellare la lettura asincrona.

Ma ancora mi danno l'eccezione errore di "Un'operazione di lettura asincrona è già in corso sul torrente 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

L'invio di parte del codice pertinente può essere d'aiuto. –

+0

Il mio codice è troppo lungo, lo mostrerò come una nuova risposta – Asker

+1

No, non è una risposta. Mettilo nella domanda. –

risposta

0

penso che ci sono due opzioni.

Se è giusto perdere un campione perché il precedente ha impiegato troppo tempo, quindi impostare un flag per indicare che si sta già campionando.

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; 
    } 
} 

Se non è ok per perdere un intervallo, si potrebbe provare la creazione di un nuovo oggetto processo per ogni chiamata, piuttosto che riutilizzare il processo esistente. Questo potrebbe creare molti bambini anche se i comandi richiedono molto tempo per essere completati.

Problemi correlati