Control de prioridad de tareas en RobotC

Round RobinEn el artículo anterior de RobotC vimos cómo manejar varias tareas, gestionando el uso de recursos compartidos como los motores. En este artículo ampliaré la información sobre el control de prioridad de tareas en RobotC, viendo cómo poner mayor o menor prioridad a una tarea, y el efecto que tiene sobre la ejecución del programa. También veremos en qué consiste la planificación de tareas Round Robin y al final pondré un par de programas de prueba con vídeos incluidos.

¿Que significa prioridad?:

A la hora de iniciar una tarea en RobotC podemos asignarle una prioridad. Esta prioridad tiene un valor numérico que va del 0 al 255. Cuando una tarea se está ejecutando en la CPU el resto de tareas están esperando a que la deje libre. La tarea que tendrá el control de la CPU después de que la tarea que la estaba utilizando la deje libre será la que mayor prioridad tenga. Esto significa que las tareas que tengan mayor prioridad se ejecutarán antes que las demás que estén esperando.

RobotC usa planificación Round Robin para asignar tiempo de CPU a cada tarea.

Planificación Round-robin:

Round robin es un método para seleccionar todos los elementos en un grupo de manera equitativa y en un orden racional, normalmente comenzando por el primer elemento de la lista hasta llegar al último y empezando de nuevo desde el primer elemento. El planeamiento Round Robin es tan simple como fácil de implementar, y está libre de inanición (significa que ningún proceso esperará durante demasiado tiempo a que le den tiempo de CPU).

Round Robin asigna a cada proceso una porción de tiempo equitativa y ordenada, por lo que ningún proceso tendrá mayor tiempo de ejecución que los demás. Normalmente Round Robin trata a todos los procesos con la misma prioridad, aunque en caso de RobotC podemos aplicar prioridades, que solo afectarán en el orden en que entren a CPU las tareas que estén esperando, pero nunca en el tiempo de CPU que se les asigne.

Tareas con prioridad en Robotc:

En RobotC se le puede asignar una prioridad a una tarea al iniciarla. Esta prioridad debe estar entre el 0 y el 255. A mayor prioridad antes se ejecutará dicha tarea. Para asignar prioridad a una tarea al iniciarla se usa la función:

StartTaskWithPriority(nombre_tarea, prioridad): Inicia una tarea con la prioridad que hayamos escogido.

Hay que tener en cuenta que la prioridad no será algo perceptible, ya que la asignación de CPUs a tareas se hace muy rápido, pero sin embargo tiene utilidad a la hora de programar, ya que nos aseguramos que ciertas tareas se ejecuten antes que otras mientras ambas estén esperando.

Programa de prueba:

Un programa bastante sencillo para probar que en efecto todas las tareas reciben el mismo tiempo de CPU es el siguiente: se crean cuatro tareas, cada una de ellas se encarga de aumentar un contador y mostrar su número por pantalla. Si todas las tareas tuvieran el mismo tiempo de CPU los números deberían avanzar a la vez.

El código es el siguiente:

int cont1 = 0, cont2 = 0, cont3 = 0, cont4 = 0;

task tarea1()
{
while(true){
wait1Msec(300);
cont1++;
nxtDisplayCenteredTextLine(0, “Tarea 1: %d”, cont1);
}
}

task tarea2()
{
while (true){
wait1Msec(300);
cont2++;
nxtDisplayCenteredTextLine(2, “Tarea 2: %d”, cont2);
}
}

task tarea3()
{
while(true){
wait1Msec(300);
cont3++;
nxtDisplayCenteredTextLine(4, “Tarea 3: %d”, cont3);
}
}

task tarea4()
{
while(true){
wait1Msec(300);
cont4++;
nxtDisplayCenteredTextLine(6, “Tarea 4: %d”, cont4);
}
}

task main()
{
StartTaskWithPriority(tarea1, 250);
StartTaskWithPriority(tarea2, 150);
StartTaskWithPriority(tarea3, 100);
StartTaskWithPriority(tarea4, 25);
while(true)
{
wait1Msec(300);
}
return;
}

Y aquí os pongo un video de su funcionamiento:

También se puede hacer una pequeñas variación, cambiando los retardos dentro de cada tarea para que sean proporcionales. Si por ejemplo ponemos a una tarea el doble de retardo que otra, está cambiará el contador a la mitad de velocidad. Aquí está un código de ejemplo:

int cont1 = 0, cont2 = 0, cont3 = 0, cont4 = 0;

task tarea1()
{
while(true){
wait1Msec(1000);
cont1++;
nxtDisplayCenteredTextLine(0, “Tarea 1: %d”, cont1);
}
}

task tarea2()
{
while (true){
wait1Msec(500);
cont2++;
nxtDisplayCenteredTextLine(2, “Tarea 2: %d”, cont2);
}
}

task tarea3()
{
while(true){
wait1Msec(250);
cont3++;
nxtDisplayCenteredTextLine(4, “Tarea 3: %d”, cont3);
}
}

task tarea4()
{
while(true){
wait1Msec(125);
cont4++;
nxtDisplayCenteredTextLine(6, “Tarea 4: %d”, cont4);
}
}

task main()
{
StartTaskWithPriority(tarea1, 250);
StartTaskWithPriority(tarea2, 150);
StartTaskWithPriority(tarea3, 100);
StartTaskWithPriority(tarea4, 25);
while(true)
{
wait1Msec(300);
}
return;
}

Y el vídeo:

En este caso la diferente espera interna de cada tarea produce que los contadores crezcan de forma inversamente proporcional, de ahí que exista una diferencia de velocidades de 1 a 8 entre la tarea 1 y la 4, la misma relación inversa que sus retardos. En este caso la prioridad de cada una de las tareas no afecta para nada al resultado: sabemos que cada vez que se han ejecutado las 4 tareas siempre ha sido la tarea 1 la primera de ellas, a continuación la 2, la 3 y finalmente la 4, debido a la siguiente parte del código:


StartTaskWithPriority(tarea1, 250);
StartTaskWithPriority(tarea2, 150);
StartTaskWithPriority(tarea3, 100);
StartTaskWithPriority(tarea4, 25);

En esta pequeña aplicación no ha afectado para nada la prioridad de ejecución, pero puede que en otra aplicación sí sea necesario el uso de prioridades.

Espero que os haya resultado interesante. Ya sabéis, ante cualquier duda estamos en el foro.

Comments are closed.