5

Estoy tratando de utilizar C# para controlar un fondo aplicación de línea de comandos, que se puede descargar aquí: http://www.ti.com/litv/zip/spmc015bexcepción de una operación de lectura asíncrona ya está en marcha en la corriente StandardOutput

Esta es una aplicación para la tensión del motor control, cuando ingreso a la aplicación, como "b.exe -c 1", la consola parece una especie de modelo de bloqueo. Cada comando en esta aplicación comienza con el símbolo "#". Ver fotos aquí:

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

Lo que estoy tratando de hacer es, utilizar StandardInput.WriteLine ("vout stat"); para medir el voltaje Esto enviará un comando "stat vout" al fondo de la consola e idealmente devolverá un valor de voltaje. En esta foto, devuelve algunos consejos de ayuda. Duing todo este tiempo, todavía está en el modo de bloqueo.

Deseo obtener el mensaje de devolución con StandardOutput.ReadLine(); pero falló. Si ReadTo End() entonces mi programa está congelado porque esta aplicación nunca regresa a la consola estándar, que está bloqueando.

Cuando probé BeginOutputReadLine(); El evento OutputDataReceived puede obtener realmente el retorno del mensaje desde la consola, como en las fotos de "stat [vout | vbus | fault". Pero se limitó en mi programa de un solo hilo.

Mi situación actual es que utilizo System.Timers.Timers en WinForms y cada segundo enviará un comando "stat vout2" para leer el voltaje, y con suerte obtener el valor de retorno.

Sin embargo, System.Timers.Timers es asincrónico, por lo que cuando llamé a BeginOutputReadLine() en este subproceso de Timers, se solicitó "Ya se inició una operación de lectura asíncrona en la secuencia". Mientras tanto, como he demostrado anteriormente, no puedo usar métodos sincrónicos como ReadLine() para obtener el valor.

¿Qué debo hacer ahora? Realmente necesito ejecutar esta aplicación de línea de comando en modo multi-threading.

Muchas gracias y deseamos a todos que tengan un buen fin de semana.

--update el abr 28 de 19:18 CST Aquí está el código fuente correspondiente:

Uno de los WinFroms botón Start() la clase SystemClock, entonces Timing.Measuring() se ejecuta cada segundo. La clase TimingController llamará a GetVoltage() y GetCurrent() al mismo tiempo durante un segundo de acuerdo con SystemClock, para medir el voltaje y la corriente.

En la clase de medida, StandardInput.WriteLine ("stat vout2"); para obtener el voltaje de la aplicación de la consola, y StandardInput.WriteLine ("stat cur"); para obtener la corriente. Ambos usan BeginOutputReadLine() para obtener el resultado dado que StandardOutput no funcionó.

Utilizo un indicador isOutputObtained para indicar si se devolvieron los datos. Cada vez que finaliza la lectura, llamé a CancelOutputRead(); para cancelar la lectura asíncrona.

Pero todavía me dan la excepción de error de "Una operación de lectura asíncrona ya está en marcha en la corriente 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

Publicar algunos de los códigos relevantes podría ayudar. –

+0

Mi código es demasiado largo, lo mostraré como una nueva respuesta – Asker

+1

No, no es una respuesta. Ponlo en la pregunta. –

Respuesta

0

yo creo que hay dos opciones.

Si se puede omitir una muestra porque la anterior tomó demasiado tiempo, establezca una bandera para indicar que ya está realizando el muestreo.

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

Si no está bien perder un intervalo, usted podría intentar crear un nuevo objeto de proceso para cada llamada en lugar de volver a utilizar el proceso existente. Sin embargo, esto podría crear muchos niños si los comandos tardan mucho tiempo en completarse.

Cuestiones relacionadas