2012-03-28 12 views
6

Ok ... esto será largo, pero primero necesito explicar algunos antecedentes.Puertos multiproceso y en serie

Esta parte de mi software es para clasificar artículos que corren por una cinta transportadora. Estoy usando Modbus para la cinta transportadora. Modbus abrirá puertas en un momento específico para permitir que un artículo atraviese la puerta. Los artículos pasarán por ciertas puertas basadas en el peso.

Estoy monitoreando un sensor para determinar cuándo un artículo está en una balanza. Cuando el sensor está bloqueado, el artículo se pesa y se envía a la puerta correspondiente. Los temporizadores están configurados para abrir/cerrar la puerta.

Mi código funcionará para esto ... el problema es que no funcionará para varios elementos. Con eso quiero decir, mientras una puerta está abierta, el sensor no está siendo monitoreado hasta que la puerta esté cerrada. Por lo tanto, mientras el elemento A está en camino a la puerta, el elemento B no se pesará en la báscula cuando bloquee el sensor. Podría tener hasta 8 artículos en la línea a la vez. Aquí está el código que estoy corriendo ahora:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
} 

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if sensor is blocked 
    if (sensorstatus == 0) 
    { 
     //the timers just start the thread 
     scaleTimer.Start(); 
    } 
    else 
    { 
     sensorTimer.Start(); 
    } 
} 

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     ReadScale(); 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     SetOpenDelay(); 
     SetDuration(); 
    } 
    } 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if gate = 0, this means the weight of meat on scale 
    //is not in any weight range. Meat runs off the end. 
    if (gate == 0) 
    { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
     sensorTimer.Start(); 
    } 
    else 
    { 
     //open gate 
     //then close gate 
    } 
    } 

Este código funciona bien, sólo hay que ser capaz de dar cuenta de varios elementos en la línea. ¿Alguna sugerencia?

También he intentado lo siguiente:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
}  

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    sensorTimer.Start(); 
} 

    private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     //sensor blocked 
     if (sensorstatus == 0) 
     { 
      ReadScale(); 
      //SaveWeight(); 
      prevgate = gate; 
      gate = DetermineGate(); 
      SetOpenDelay(); 
      SetDuration(); 

      //if gate = 0, this means the weight of meat on scale 
      //is not in any weight range. Meat runs off the end. 
      if (gate == 0) 
      { 
      txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
      } 
      else 
      { 
      //open gate 
      //close gate 
      } 
    } 
} 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    scaleTimer.Start(); 
} 

Cuando hice esto, empecé a ambos hilos cuando se pulsa el botón de inicio. Recibo todo tipo de excepciones y el programa finalmente arroja SEHException y se cuelga. Los otros errores que recibo dicen "Puerto serie ya abierto" o "Error de E/S".

+0

es el problema de que las secuencias de roscado escala durante DetermineGate(), SetOpenDelay() y SetDuration()? Todavía no entiendo completamente tu código. Parece que sigue siendo muy de procedimiento aunque esté utilizando subprocesos: parece que los subprocesos siempre están esperando el uno al otro. ¿Esto es lo que está pasando? –

+0

FYI, aquí hay un gran enlace en multiprocesamiento en C#: http://www.yoda.arachsys.com/csharp/threads/index.shtml –

+0

Esta es mi primera vez multiproceso.Lo necesitaba donde mi GUI no se cerraría. No estoy seguro de lo que quiere decir con "bloques de escala de hilo". Los hilos están esperando uno al otro ... pero cuando traté de solucionarlo, acabo de recibir un montón de errores (vea mi edición). Necesito este software para poder ejecutar una cinta transportadora. Debe tener en cuenta los elementos que pasan por el sensor a una velocidad de, por ejemplo, 1 elemento cada 3 segundos. Entonces todas las puertas deben abrirse/cerrarse cuando el artículo llegue a su puerta. Sé que esto suena confuso ... ¿entiendes lo que estoy tratando de lograr? Gracias por el enlace – CSharpDev

Respuesta

1

Sugeriría que su mejor opción es probablemente crear un hilo dedicado para sentarse en cada puerto serie. Tal enfoque no requerirá, ni prohibirá, ninguna similitud en la forma en que se manejan los puertos, evitará cualquier interferencia en la operación entre los puertos, y será escalable dentro de límites razonables (usar un hilo para cada uno de los 32 puertos estaría bien; un hilo por cada uno de 1,000 sería malo). Aunque uno debe evitar crear subprocesos que simplemente se ejecutarán durante un tiempo breve y dejar de fumar, o crear un gran número de subprocesos, usar un subproceso dedicado para cada puerto serie garantizará que cuando lleguen los datos habrá un subproceso listo para manejarlo.

+0

Intenté esto. Tenía un hilo dedicado al sensor y otro dedicado a la báscula. El hilo de la escala solo pesaba el peso si el sensor estaba bloqueado (algo estaba en la balanza). Luego, una vez que obtuve el peso, generaría un hilo para manejar las puertas. Sin embargo, nunca llegaría a ese hilo porque tengo errores al leer la escala y el sensor. Esos dos hilos no funcionarían juntos. Están en diferentes puertos COM y todo, así que no estoy seguro de cuál es – CSharpDev

+0

Mi sugerencia habría sido lanzar todos los hilos al inicio y simplemente dejarlos en ejecución. Iniciar hilos es costoso. Dejar un hilo continuamente ejecutando el código inútilmente es muy costoso. Sin embargo, dejar un hilo suelto bloqueado esperando E/S es comparativamente mucho más económico. No es tan barato como para tener cientos corriendo sin ninguna razón, pero lo suficientemente barato como para que ocho no sean un gran problema. – supercat

1

Me di cuenta de que no tienes ningún bucle en los métodos DoWork de tu hilo. Ese sería un gran lugar para comenzar. El subproceso de trabajo debe ser un bucle que no retorna hasta que CancellationPending se establece en verdadero. No se enredarán solo porque lo tiene en un hilo: el hilo se ejecutará hasta que finalice, luego saldrá.

Editado para agregar: Lo que parece que se está perdiendo es que necesita dividir el código que controla la escala y el código que abre y cierra la puerta. Una forma de hacerlo sería tener un ciclo infinito que supervise la báscula y, cuando detecte algo, comience un nuevo hilo que maneje la apertura y el cierre de la puerta.

+0

Gracias Charlie (y Tom) por el voto popular. Por lo que entendí, creo que el ciclo es "causado" por un hilo que llama al otro. – AlexDev

+0

Tengo una pregunta, pero luego el OP sigue usando el código de procedimiento: un método no se ejecutará hasta que el otro método lo llame. La idea de enhebrar es tener un código que se ejecute independientemente de otro, y cuando encuentra algo que es extenso (como abrir y cerrar las puertas), genera ese trabajo en un nuevo hilo. ¿O me estoy perdiendo algo? –

+0

Bucle el hilo en el método RunWorkerCompleted. Se inicia un temporizador que llama al hilo después de que funcione. – CSharpDev

2

Creo que necesitas algo como esto. No sé si son necesarias las cerraduras pero yo les añadí para la seguridad, ya que está recibiendo errores

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int sensor = 1; 
    while(!SensorThread.CancellationPending == true) 
    { 
     int newSensor; 
     lock(this) 
     { 
      newSensor = ReadSensor(); 
     } 

     //sensor state changed 
     if(newSensor != sensor) 
     { 
      //sensor was 1 and changed to 0 
      if(newSensor==0) 
      { 
       scaleTimer.Start(); 
      } 
      sensor = newSensor; 
     } 
     Thread.Sleep(1); 
    } 
    e.Cancel = true; 
}  

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //sensor blocked 
    //if (sensorstatus == 0) 
    { 
     lock(this) 
     { 
      ReadScale(); 
     } 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     lock(this) 
     { 
      SetOpenDelay(); 
      SetDuration(); 
     } 

     //if gate = 0, this means the weight of meat on scale 
     //is not in any weight range. Meat runs off the end. 
     if (gate == 0) 
     { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                      "lbs is out of range"}); 
     } 
     else 
     { 
     lock(this) 
     { 
     //open gate 
     } 
     lock(this) 
     { 
     //close gate 
     } 
     } 
    } 
+0

Entonces, ¿el nuevoSensor debería comenzar como un valor verdadero? ¿Puedes elaborar un poco sobre lo que estás haciendo aquí? – CSharpDev

+0

Se corrigió la inicialización del nuevoSensor. La idea, como otros lo han sugerido, es que el hilo del sensor se bucles revisando el sensor y cuando detecta un cambio en el estado, desencadena el hilo de la escala. – AlexDev

+0

Voy a dar una oportunidad y ver qué pasa. ¡Gracias! – CSharpDev

Cuestiones relacionadas