Go Down

Topic: Procesos en paralelo, multihilo, simultaneos y otras yerbas (Read 6965 times) previous topic - next topic

PeterKantTropus

Jul 23, 2016, 06:56 pm Last Edit: Aug 30, 2019, 02:13 pm by PeterKantTropus
Editado 10.01.2019


Cada tanto aparecen preguntas sobre estos tópicos en foro. En algunos casos son preguntas validas sobre procesos en paralelo, pero en la mayoría de las ocasiones se trata de un mal diseño de funciones.
Generalmente es un intento de integrar dos o mas códigos que funcionan bien por separados, pero juntos tienen comportamientos inesperados.
Por ese motivo me decidí a escribir un modesto tutorial   sobre el tema, utilizando dos funciones de lo mas sencillas.
Las funciones están basadas en los ejemplos blink y blinkWithoutDelay

Pero antes un break  culinario.  Prepararemos una exquisita receta: un huevo duro


Receta de principiante

1 tomar un huevo
2 ponerlo en un recipiente, con agua, sobre el fuego.
3 esperar 10 minutos, sin hacer nada.
4 sacar el huevo.

Receta de masterchef para preparar un huevo duro

1 ¿Estamos preparando un huevo duro en este momento?
2 si la respuesta es no
  2.1  tomar un huevo
  2,2 ponerlo en un recipiente con agua sobre el fuego.
3 si  la respuesta a la pregunta 1 es si
  3.1  ¿ya pasaron  10 minutos?
  3.2  si la respuesta de la pregunta 3.1 es no: hacer otra cosa      
  3.2  si la respuesta de la pregunta 3.1 es si: sacar el huevo.

sin duda  la segunda receta parece mas complicada, sobre todo porque al final tenemos un huevo duro, pero   es lo que hacemos en la realidad, cuando cocinamos no nos quedamos diez minutos viendo como hierve el huevo, nos ponemos a hacer otra cosa en esos diez minutos. Por eso para un observador externo parece que un cocinero esta haciendo varias recetas al mismo tiempo. Sin embargo, si intentamos unir varias recetas del primer tipo , a comida se alarga en el tiempo y parecerá que el cocinero se la pasa esperando.



Ahora un ejemplo de Arduino
El objetivo del programa es encender dos leds, uno rojo y otro verde, a diferentes frecuencias.

Led rojo con delays parpadeando cada 500 ms

Code: [Select]
int ledRojo = 14;
void setup() {                
  pinMode(ledRojo, OUTPUT);    
}

void loop() {
LedRojo;
}

void LedRojo()
{
  digitalWrite(ledRojo, HIGH);  
  delay(500);              
  digitalWrite(ledRojo, LOW);    
  delay(500);              
}


El mismo caso, pero sin delay  

Code: [Select]

const int ledPinRojo =  14;      // the number of the LED pin


int ledStateRojo = LOW;             // ledState used to set the LED
long previousMillisRojo = 0;        // will store last time LED was updated
long intervalRojo = 500;           // interval at which to blink (milliseconds)

void setup() {
   pinMode(ledPinRojo, OUTPUT);      
}

void loop()
{
LedRojo ;
}


void LedRojo()
{
  unsigned long currentMillis = millis();
   if(currentMillis - previousMillisRojo > intervalRojo) {
     previousMillisRojo = currentMillis;  
      if (ledStateRojo == LOW)
      ledStateRojo = HIGH;
       else
      ledStateRojo = LOW;
     digitalWrite(ledPinRojo, ledStateRojo);
  }
}


En ambos casos se comportan igual



Las funciones para un led Verde son equivalentes (parpadeando a un segundo)

Code: [Select]
int ledVerde = 15;
void setup() {                
  pinMode(ledVerde, OUTPUT);    
}

void loop() {
LedVerde;
}

void LedVerde()
{
  digitalWrite(ledVerde, HIGH);  
  delay(1000);              
  digitalWrite(ledVerde, LOW);    
  delay(1000);              
}



Y su equivalente sin delay

Code: [Select]
const int ledPinVerde =  15;      // the number of the LED pin
int ledStateVerde = LOW;             // ledState used to set the LED
long previousMillisVerde = 0;        // will store last time LED was updated
long intervalVerde = 1000;           // interval at which to blink (milliseconds)

void setup() {
   pinMode(ledPinVerde, OUTPUT);      
}

void loop()
{
LedVerde ;
}


void LedVerde()
{
  unsigned long currentMillis = millis();
   if(currentMillis - previousMillisVerde > intervalVerde) {
     previousMillisVerde = currentMillis;  
      if (ledStateVerde == LOW)
      ledStateVerde = HIGH;
       else
      ledStateVerde = LOW;
     digitalWrite(ledPinVerde, ledStateVerde);
  }


}


En ambos casos el comportamiento final es el mismo.






Hasta aquí parece una complicación sin sentido no utilizar  delays , pero cuando se integra el codigo

con delays el programa tiene un comportamiento inesperado.



Code: [Select]
int ledRojo = 14;
int ledVerde = 15;

void setup() {                
  pinMode(ledRojo, OUTPUT);  
  pinMode(ledVerde, OUTPUT);
}

void loop() {
LedRojo;
LedVerde;
}

void LedRojo()
{
  digitalWrite(ledRojo, HIGH);  
  delay(500);              
  digitalWrite(ledRojo, LOW);    
  delay(500);              
}

void LedVerde()
{
  digitalWrite(ledVerde, HIGH);  
  delay(1000);              
  digitalWrite(ledVerde, LOW);    
  delay(1000);              
}




El problema reside en las funciones, se completan antes de devolver el control a la función void loop, por lo tanto se ejecutan en serie, es decir una detrás de la otra.

Es en este momento cuando aparecen los post de mulhilo y procesos en paralelo.
Sin embargo el código integrado sin utilizar delays funciona correctamente


Code: [Select]

const int ledPinRojo =  14;      // the number of the LED pin


int ledStateRojo = LOW;             // ledState used to set the LED
long previousMillisRojo = 0;        // will store last time LED was updated
long intervalRojo = 500;           // interval at which to blink (milliseconds)

const int ledPinVerde =  15;      // the number of the LED pin
int ledStateVerde = LOW;             // ledState used to set the LED
long previousMillisVerde = 0;        // will store last time LED was updated
long intervalVerde = 1000;           // interval at which to blink (milliseconds)

void setup() {
   pinMode(ledPinRojo, OUTPUT);
   pinMode(ledPinVerde, OUTPUT);  
}

void loop()
{
LedRojo ;
LedVerde ;
}


void LedRojo()
{
  unsigned long currentMillis = millis();
   if(currentMillis - previousMillisRojo > intervalRojo) {
     previousMillisRojo = currentMillis;  
      if (ledStateRojo == LOW)
      ledStateRojo = HIGH;
       else
      ledStateRojo = LOW;
     digitalWrite(ledPinRojo, ledStateRojo);
  }
}


void LedVerde()
{
  unsigned long currentMillis = millis();
   if(currentMillis - previousMillisVerde > intervalVerde) {
     previousMillisVerde = currentMillis;  
      if (ledStateVerde == LOW)
      ledStateVerde = HIGH;
       else
      ledStateVerde = LOW;
     digitalWrite(ledPinVerde, ledStateVerde);
  }


}





Como conclusión podemos decir que en la mayoría de los casos no son necesarios procesos en paralelos y se debe evitar a toda costa utilizar delays y otras estructuras que detengan el programa en algún punto.

Saludos
"Si no entra como tornillo, entra como clavo"


everbetz


overhax

Como puedo hacer si necesito controlar también las cantidad de veces que cada led (rojo y verde) se encenderá y apagara?

Go Up