Sistemas informáticos de tiempo real

Anuncio
Sistemas informáticos en tiempo real
Práctica 5
Hilos (Thread)
Objetivos generales
•
•
Aprender la programación multihebras o multihilos del S.O.
Profundizar en el entorno de depuración de C++ y Tslite del S.O.
Práctica
En esta práctica se partirá del programa ejemplo suministrado por el S.O. por lo
que no se necesitará escribirlo. El programa arranca cinco hilos, cuya tarea es imprimir
tres veces un mensaje. La práctica tiene los siguientes objetivos:
1. Comprender el programa así como las distintas funciones del S.O.
2. Utilizando el entorno de depuración determinar las prioridades asignadas por
defecto a las cinco hebras.
3. Cambiar las prioridades asignadas por defecto asignando por orden creciente a la
primera hebra arrancada la prioridad más baja y a la última la más alta.
4. Utilizando el entorno de depuración comprobar las nuevas prioridades.
El programa se muestra en las hojas siguientes así como la explicación la definición
de las funciones.
Indicaciones
•
•
Para comprobar las prioridades asignadas a las hebras será necesario detener el
depurador en una línea en la que ya esté creada la tarea, o en una línea en la que ya
estén todas creadas. En este momento se elige el menú de información de target
system y aquí se puede observar toda la información relativa a las hebras.
El ETS Kernel tiene definido un rango de prioridades desde -15 (la más baja) a 15
(la más alta). La función que permite cambiar la prioridad de una hebra definida en
el fichero <winbase.h> es:
BOOL SetThreadPriority(
HANDLE hThread,
int nPriority
);
Donde
hThread
nPriority
es el HANDLE de la hebra a la que se quiere cambiar la prioridad
es la nueva prioridad que se le asigna a la hebra
// RTHELLO.C -- Multithreaded (real-time) hello world program
// Copyright (c) 1998 Phar Lap Software, Inc. All rights reserved.
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <embkern.h>
#define STACK_SIZE (16 * 1024)
void OneHello(void *id);
volatile DWORD alive;
int num_threads = 5;
void main()
{
int i;
int id = 0;
HANDLE hThread;
char ThreadName[32];
// start threads
for (i = 0 ; i < num_threads ; i++)
{
hThread = (HANDLE) _beginthread(OneHello, STACK_SIZE,
(void *) id);
if (hThread != (HANDLE)-1)
{
sprintf(ThreadName, "OneHello %c", 'A' + id);
EtsSetThreadDebugName(hThread, ThreadName);
++id;
InterlockedIncrement((LPLONG)&alive);
}
}
while (alive)
Sleep(50);
printf("main thread terminates\n");
exit(0);
}
void OneHello(void *id)
{
int i;
for(i = 0; i < 3; ++i)
printf("Hello From Thread %c\n", 'A' + (int)id);
InterlockedDecrement((LPLONG)&alive);
_endthread();
}
Aclaraciones:
HANDLE
HANDLE es un valor entero único, utilizado por windows para identificar un
objeto. El ETS kernel presenta en algunas funciones el mismo interfaz de windows. Este
caso es una de ellas.
Volatile
Esta cláusula añadida a una variable indica al compilador que esta variable
puede ser modificada por otra entidad u otra función distinta a la que está procesando
por lo que no debe optimizar. Por ejemplo en el siguiente trozo de código:
int a, valor1;
:
:
a=valor1;
if (a !=0)
:
:
El compilador podría optimizar y en la sentencia if chequear el valor de la variable
valor1 y no el valor de A que es el que realmente cambia;
EtsSetThreadDebugName:
Asigna al objeto HANDLE un nombre simbólico que aparece cuando utilicemos
el depurador.
sprintf:
Escribe datos formateados en un string.
Sleep():
Suspende la ejecución por el tiempo especificado.
_beginthread:
Permite crear una hebra. Pertenece a la librería de run-time de Visual C++
_endthread:
Finaliza una hebra. Pertenece a la librería de run-time de Visual C++
Sistemas informáticos en tiempo real
Práctica 6
Suspender y reanudar (dormir y despertar)
Objetivos generales
•
•
•
Aprender la programación multihebras o multihilos del S.O.
Aprender a Suspender y reanudar hilos.
Profundizar en el entorno de depuración de C++ y Tslite del S.O.
Práctica
Se desea hacer una aplicación multihilos, con tres hilos H1,H2, H3.
La función de cada hilo será imprimir un mensaje indicando que hilo es, esperá un
tiempo, reanudará el siguiente hilo y se suspenderá. Es decir:
1. H1 imprimirá un mensaje esperará un segundo, despertará a H2 y se dormirá.
2. H2 imprimirá un mensaje esperará dos segundos, despertará a H3 y se dormirá.
3. H3 imprimirá un mensaje esperará tres segundos, despertará a H1 y se dormirá.
El programa realizará este ciclo cinco veces, y finalizará.
Indicaciones
• Para suspender y reanudar un hilo se utilizarán las siguientes funciones:
Para suspender un hilo:
DWORD SuspendThread(HANDLE hThread);
Para reanudar un hilo:
DWORD ResumeThread(HANDLE hThread);
•
•
Para esperar el tiempo requerido utilícese la función Sleep empleada en la práctica
anterior.
Para controlar el número de veces que se realizará el ciclo debe utilizarse una
variable compartida.
Sistemas informáticos en tiempo real
Práctica 7
Exclusión mutua
Objetivos generales
•
•
•
Aprender la programación multihilos del S.O.
Comprender la exclusión mutua.
Profundizar en el entorno de depuración de C++ y Tslite del S.O.
Práctica
Con esta práctica se pretende observar la importancia de conseguir la exclusión
mutua cuando varios hilos comparten variables. La práctica consistirá de las siguientes
partes:
1. Estudiar el código que acompaña a la práctica, localizando los problemas de
exclusión mutua.
2. Ejecutar el código para observar que estos problemas se producen fácilmente.
3. Añadir el código necesario para implementar la solución de Peterson y conseguir
así exclusión mutua.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <process.h>
#include <embkern.h>
#define STACK_SIZE (16 * 1024)
void hilo1(void *id);
void hilo2(void *id);
volatile DWORD variable_compartida ;
BOOL salir = FALSE;
HANDLE hThread1,hThread2;
void main()
{ int id = 0;
// start threads
hThread1 = (HANDLE) _beginthread(hilo1, STACK_SIZE,(void *) id);
if (hThread1 != (HANDLE)-1)
EtsSetThreadDebugName(hThread1, "hilo1");
hThread2 = (HANDLE) _beginthread(hilo2, STACK_SIZE,(void *) id);
if (hThread2 != (HANDLE)-1)
EtsSetThreadDebugName(hThread2, "hilo2");
for(;salir!=TRUE;);
Sleep(100);
printf("main thread terminates\n");
exit(0);
}
void hilo1(void *id)
{
for(;salir!=TRUE;)
{
// sección crítica
variable_compartida=1;
if (variable_compartida!=1) salir=TRUE;
}
printf("hilo1 finalizado\n");
_endthread();
}
void hilo2(void *id)
{
for(;salir!=TRUE;)
{
// sección crítica
variable_compartida=2;
if (variable_compartida!=2) salir=TRUE;
}
printf("hilo2 finalizado\n");
_endthread();
}
Sistemas informáticos en tiempo real
Práctica 8
Productor-consumidor
Objetivos generales
•
•
•
•
•
Aprender la programación multihilos del S.O.
Comprender la exclusión mutua.
Profundizar en el entorno de depuración de C++ y Tslite del S.O.
Regiones críticas.
Implementar el modelo productor consumidor (reducido).
Práctica
En esta práctica se va a implementar el modelo del productor-consumidor en una
versión reducida, es decir en lugar de tener distintos buffers, tendremos una variable
donde el productor aleatoriamente pondrá un dato y lo recogerá el consumidor. Cada
vez que el productor ponga un dato en esta variable activará un flag para indicar que el
dato es válido. Cada vez que el consumidor lea el dato y este dispuesto a recibir uno
nuevo pondrá el flag inactivo, momento en el que el productor podrá poner un nuevo
dato. El dato que recoja el consumidor se mostrará por pantalla
Indicaciones
El dato que va a poner el productor puede ser cualquiera, por ejemplo un número
entero que se incrementará. El momento en el que el productor ponga el dato o el
consumidor lo recoja debe ser aleatorio, para lo cual se utilizará la función Sleep con un
valor de tiempo aleatorio. Para comprobar que el funcionamiento del programa es
correcto se deberá mostrar los datos que pone el productor y lee el consumidor por
pantalla para comparar que son iguales.
El kernel ETS mantiene compatibilidad con la API Win32. La API WIN32 define
dos objetos distintos que se pueden utilizar como semáforos: mutex y critical section.
Ambos objetos dan el mismo servicio. La diferencia es que el objeto critical section se
utiliza para hilos del mismo proceso y el objeto mutex se puede utilizar además, para
hilos de distintos procesos. El objeto critical section es menos costoso que el objeto
mutex. En el caso del kernel ETS vamos a utilizar el objeto critical section ya que es un
kernel multihilo pero con un solo proceso.
Para el caso de objetos critical section se debe definir como un tipo de dato
CRITICAL_SECTION. Se tiene las siguientes funciones, donde CritSec es el objeto
CRTICAL_SECTION:
•
•
•
InitializeCriticalSection(&CritSec); Inicializa el objeto critical Section
EnterCriticalSection(&CritSec); Se llama a esta función para entrar en la
sección crítica seria lo equivalente a la función DOWN para semáforos binarios
explicada en clase de teoría.
LeaveCriticalSection(&CritSec); Se llama a esta función para salir de la sección
crítica. Sería equivalente a la función UP para un semáforo binario.
Descargar