• No se han encontrado resultados

Tema 6.2: Programación de Sistemas en Tiempo Real

N/A
N/A
Protected

Academic year: 2021

Share "Tema 6.2: Programación de Sistemas en Tiempo Real"

Copied!
12
0
0

Texto completo

(1)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 1

1

Tema 6.2:

Tema 6.2:

Programación de Sistemas en Tiempo

Programación de Sistemas en Tiempo

Real

Real

INDICE:

hContenedores de datos

–Array, array circulares, FIFO y listas

hProcesos e hilos

hSincronización de hilos

h Arrays o tablas de datos

– No almacena información sobre los límites.

– No se comprueba si se está accediendo fuera de la zona

reservada.

– Se pueden acceder con índices Æ código poco eficiente:

Dir_efectiva = Dir_base + Índice * Tamaño_Elemento

– Acceso con punteros más eficiente

#include <stdlib.h>

struct dato {

long num; char car; };

struct dato g_aDato[10]; int main() { int i; for (i = 0; i < 10; ++i) { g_aDato[i].num = rand(); g_aDato[i].car = ‘A’; } return 0; } #include <stdlib.h> struct dato { long num; char car; };

struct dato g_aDato[10]; int main()

{

struct dato* it;

for (it = g_aDato; it < (g_aDato+10); ++it) {

(*it).num = rand(); // También it-> en lugar de (*it). (*it).car = 'A';

}

return 0; }

(2)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 3

3

h Array circular

– Aunque el array siempre se almacena de manera lineal, a veces

es interesante crear la ilusión de acceso a una ruleta.

– La posición 8 debería se convertida a la posición 0.

char achLetras[8]; char *pchLetra;

/* Acceso mediante indexación */ achLetras[0] = ‘a’;

achLetras[1] = ‘b’; achLetras[5] = ‘f’;

/* Acceso mediante punteros */ pchLetra = achLetras;

*(pchLetra++) = ‘a’; *pchLetra = ‘b’; *(pchLetra += 4) = ‘f’;

achLetras[i >= 8 ? i-8 : i] /* no tiene en cuenta valor de i > 16 */

achLetras[i % 8] /* El coste computacional de la operacion % es muy alto */

achLetras[i & (8-1)] /* Solo es aplicable cuando num elementos es potencia de 2 */

Tema 6.2: Programación de Sistemas en Tiempo Real

h Contenedor de datos que permite almacenar datos y

recuperarlos más tarde respetando el orden en el que

fueron introducidos.

h Se utiliza como memoria intermedia para adaptar la

velocidad entre el consumidor y el generador de datos.

h Se usan dos funciones: una para almacenar y otra para

recuperar.

h Es necesario tener un índice para saber cual es el ultimo

elemento, y otro para saber cual el primero.

h También es necesario un contador para saber cuantos

elementos hay en el buffer, y cuantos quedan libres.

h Un ejemplo de implementación con arrays circulares

(3)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 5

5

#define NUM_ELEM (1<<4) typedef char dato_t;

static dato_t g_aDato[NUM_ELEM]; /* Buffer */

static int g_nLibres = NUM_ELEM; /* Elementos libres disponibles */ static int g_iIn = 0, g_iOut = 0;/* Índices de entrada y salida */ int InsertaDato(dato_t dato)

{

if(g_nLibres <= 0)

return -1; /* Error */ g_aDato[g_iIn] = dato;

g_iIn = (g_iIn + 1) & (NUM_ELEM - 1); --g_nLibres;

return 0; /* Éxito */ }

int ExtraeDato(dato_t *pdato) {

if(g_nLibres >= NUM_ELEM) return -1; /* Error */ *pdato = g_aDato[g_iOut];

g_iOut = (g_iOut + 1) & (NUM_ELEM - 1); g_nLibres++; return 0; /* Éxito */ } int NumLibres() { return g_nLibres; } #ifndef TAM_FIFO #define TAM_FIFO 25 #endif #ifndef TIPO #define TIPO char #endif

static TIPO *pMete; /* Puntero a donde meter el siguiente */ static TIPO *pSaca; /* Puntero a donde sacar el siguiente */ /* FIFO estará vacío si pMete == pSaca */

/* FIFO estará lleno si pMete+1 == pSaca */

static TIPO buffer[TAM_FIFO]; /* Los datos del FIFO alojados estáticamente */

/*---IniciaFifo---Vaciar el buffer fifo Entradas: ninguna Salidas: ninguna */ void IniciaFifo(void) {

pMete = pSaca = &buffer[0]; /* Vacío si pMete == pSaca */ }

(4)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 7

7

/*---MeteFifo---Introducir un dato al fifo

Entradas: dato

Salidas: cierto si quedan más elementos libres */ int MeteFifo(TIPO dato)

{

TIPO *pTemp; pTemp = pMete + 1;

if (pTemp == &buffer[TAM_FIFO]) /* se necesita envolver */ pTemp = &buffer[0];

if (pTemp == pSaca ){ /* El fifo estaba lleno */

return(0); /* No quedan más elementos libres*/ }

else{

*pMete = dato; /* Meter el dato en el fifo */ pMete = pTemp; /* Se actualiza el puntero */ return(1); /* Quedan más elementos libres */ }

}

/*---SacaFifo---Extrae un dato del fifo

Entradas: puntero a la variable donde almacenar el dato. NULL para desperdiciar el dato.

Salidas: cierto si quedan más datos */ int SacaFifo(TIPO *pDato)

{

if (pMete == pSaca)

return(0); /* Se ha vaciado el fifo */ if(pDato)

*pDato = *pSaca;

if (++pSaca == &buffer[TAM_FIFO]) pSaca = &buffer[0];

return(1); /* Quedan datos */ }

Tema 6.2: Programación de Sistemas en Tiempo Real

h Ejercicio:

Un sistema informático dispone de una función NuevoDato que es llamada en

respuesta a una interrupción para pasar un dato que acaba de ser leído de un

muestreador externo. Se genera un dato cada 32μs. Es necesario proporcionar

una salida por cada dato de entrada correspondiente a la suma promediada de los

cuadrados de los últimos 64 datos recibidos.

siendo Entrada[0] el último dato leído, Entrada[1] el anterior, …

Esta salida será almacenada en un buffer FIFO intermedio. El programa

consumidor de datos se ejecuta de media 6000 veces por minuto, siendo el

tiempo máximo entre activaciones sucesivas de 0,02s. En cada ejecución retirará

todos los datos que pueda el buffer.

Calcule el tamaño mínimo del buffer, y escriba el cuerpo de la función NuevoDato,

supuesto que se requiere que ocupe poco espacio y sea lo más rápido posible, y

que puede insertar datos sin peligro en el buffer mediante la función InsertarDato.

void NuevoDato(char dat);

int InsertaDato(long dat);

[ ]

2 63 0

64

n

Entrada

n

Salida

=

=

(5)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 9

9

h Contendor que permite cambiar de manera dinámica la cantidad de

elementos

h Enlazan unos datos con otros, de manera que pueden se accedido

de manera secuencial

h Cada elemento debe tener un puntero al siguiente elemento en la

lista

h Lista simplemente enlazada: cuando cada elemento solo tiene un

puntero al siguiente elemento

h Lista doblemente enlazada: cuando cada elemento tiene un puntero

al siguiente y otro al anterior

Contenedores de datos: Listas simplemente

Contenedores de datos: Listas simplemente

enlazadas

enlazadas

hLista con número fijo de elementos.

struct SNodoLista {

int m_iID;

char m_achNombre[40]; short m_shNacimiento;

struct SNodoLista *m_pNext; // Referencia al siguiente elemento de la lista } ;

int main() {

struct SNodoLista nodo[10]; struct SNodoLista * pCabeza; nodo[0].m_iID = 8273;

strncpy(nodo[0].m_achNombre, "Daniel", sizeof(nodo[0].m_achNombre)-1); nodo[0].m_shNacimiento = 1977;

// . . . Se rellenan otros datos

// Hacemos que nodo[1] sea el primer nodo, // nodo[2] el segundo, y nodo[0] el tercero pCabeza = &nodo[1];

nodo[1].m_pNext = &nodo[2]; nodo[2].m_pNext = &nodo[0];

nodo[0].m_pNext = 0; // Referencia nula return 0;

(6)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 11

11

hLista con reserva dinámica de memoria

struct SNodoLista {

struct SNodoLista *m_pNext; // Referencia al siguiente elemento de la lista int m_iID;

char m_achNombre[40]; short m_shNacimiento; } ;

struct SNodoLista* NuevoElemento() {

struct SNodoLista *pNodo;

pNodo = (struct SNodoLista *) malloc(sizeof(struct SNodoLista)); if(pNodo == NULL)

return NULL;

printf("Introduzca id, nombre, y año de nacimiento.\n");

if(scanf("%d %s %hd",&pNodo->m_iID, &pNodo->m_achNombre, &pNodo->m_shNacimiento) != 3) { free(pNodo); return NULL; } pNodo->m_pNext = NULL; return pNodo; }

void Encola(struct SNodoLista *pOrigen, struct SNodoLista *pNodo) {

struct SNodoLista *it;

for(it = pOrigen; it->m_pNext; ++it);

// Recorrerla hasta el último elemento it->m_pNext = pNodo;

}

int main() {

struct SNodoLista *pCabeza = NULL; pCabeza = NuevoElemento();

while(1) // Un número indeterminado de veces { // . . . Encola(pCabeza, NuevoElemento()); } return 0; }

Tema 6.2: Programación de Sistemas en Tiempo Real

Contenedores de datos: Listas simplemente

Contenedores de datos: Listas simplemente

enlazadas

enlazadas

h Ahora se podría recorrer

la lista con un bucle

h El uso de lista permita la

inserción y extracción de

elemento de manera

sencilla, tan sólo

actualizando los punteros

// Cuenta las letras de todos los nombres que se han

// incluido en la lista. Devuelve el nº de nodos encontrados. int CuentaLetras(struct SNodoLista *pNodo, int *pNoLetras) { int iNoNodos = 0; *pNoLetras = 0; while(pNodo) { *pNoLetras += strlen(pNodo->m_achNombre); pNodo = pNodo->m_pNext; iNoNodos++; } return iNoNodos; }

(7)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 13

13

Contenedores de datos: Listas simplemente

Contenedores de datos: Listas simplemente

enlazadas

enlazadas

Ejercicios:

1.

Escribir el código necesario para liberar la

memoria que se había reservado para la lista

dinámica cuya cabeza está en:

struct SNodoLista *pCabeza;

2.

Escribir el código necesario para insertar un nuevo

nodo apuntado por pNuevo inmediatamente

después de pNodo, siendo ambas variables del

tipo

struct SNodoLista *.

Contenedores de datos: Listas doblemente

Contenedores de datos: Listas doblemente

enlazadas

enlazadas

h Las lista doblemente enlazadas pueden ser recorridas en ambos sentidos,

gracias que cada elemento tiene un puntero al siguiente y otro al anterior.

(8)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 15

15

Contenedores de datos: Listas doblemente

Contenedores de datos: Listas doblemente

enlazadas

enlazadas

/// Número máximo de nodos permitido #define NUM_NODES 20

#ifndef NULL /// Puntero nulo. #define NULL 0

#endif

/** Estructura con datos relativos al estado del proceso. */ typedef struct node_data_

{

int num; }node_data;

/** Elemento de la lista de procesos.*/ typedef struct node_

{

node_data data;

// Datos para almacenar el estado del proceso. struct node_ *pPrev, *pNext;

// Punteros anterior y posterior a hilos de igual // prioridad

}node;

/** Almacén de nodos para todas las listas.

* Contenedor de todos los nodos a usar, y punteros a sus cabeceras.*/

typedef struct list_static_nodes_ {

node aNodes[NUM_NODES];

// Array de nodos. Para no usar memoria dinámica. node* pHeadFree;

// Puntero a la cabeza de la lista de nodos libres. node* pHead; // Puntero a la cabeza de la lista.

}list_static_nodes;

/** Inicia la estructura apuntada por pList del tipo * list_static_nodes para poder ser utilizada por * otras funciones.

* - pList [in, out] Puntero al array de listas * a ser iniciadas.

* retorna 0. */

short InitStaticNodesList(list_static_nodes* pList) { node *pNode; memset(pList, 0, sizeof(*pList)); pNode = &pList->aNodes[0]; pList->pHeadFree = pNode; pList->pHead = NULL;

for(int i = 1; i < NUM_NODES; i++) {

node *pCurNode = &pList->aNodes[i]; pCurNode->pPrev = pNode; pNode->pNext = pCurNode; pNode = pCurNode; } pNode->pNext = &pList->aNodes[0]; pList->pHeadFree->pPrev = pNode; return 0; };

Tema 6.2: Programación de Sistemas en Tiempo Real

Contenedores de datos: Listas doblemente

Contenedores de datos: Listas doblemente

enlazadas

enlazadas

/** Extrae el nodo apuntado por pNode de la lista * especificada por pList.

* - pList [in, out] Array de listas de donde se * obtiene el nodo.

* - pNode [in, out] Puntero al nodo que se pretende * extraer de la lista.

* retorna 0 */

short ExtractNode(list_static_nodes* pList, node* pNode) {

pNode->pPrev->pNext = pNode->pNext; pNode->pNext->pPrev = pNode->pPrev; if(pList->pHead == pNode)

{

if(pNode->pNext == pNode /* || pNode->pPrev == pNode */) pList->pHead = NULL;

else

pList->pHead = pNode->pNext; }

else if(pList->pHeadFree == pNode) {

if(pNode->pNext == pNode /* || pNode->pPrev == pNode */) pList-> pHeadFree = NULL;

else

pList-> pHeadFree = pNode->pNext; }

pNode->pNext = pNode->pPrev = NULL; return 0;

}

/** Inserta el nodo apuntado por pNode en la lista * especificada por pList.

* - pList [in, out] Lista en donde se inserta el * nodo.

* - pNode [in, out] Puntero al nodo que se pretende * insertar en la lista.

* retorna 0. */

short InsertNode(list_static_nodes* pList,node* pNode) { node* pHead; pHead = pList->pHead; if(pHead == NULL) { pList->pHead = pNode;

pNode->pNext = pNode->pPrev = pNode; return 0; } pNode->pPrev = pHead; pNode->pNext = pHead->pNext; pHead->pNext = pNode; pNode->pNext->pPrev = pNode; return 0; }

(9)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 17

17

h Un proceso es un programa en ejecución

h Tiene todos los recursos necesarios para por ejecutarse,

los más importantes:

– Memoria

– Hilo principal (cada proceso tendrá por lo menos un hilo)

h A lo largo de la ejecución puede pedir mas recursos:

– Ventanas, ficheros, nuevos hilos

h Todos estos recursos estás asignados al proceso

independientemente de donde se crearan.

h Para crear un proceso desde un programa:

CreateProcess

(ver práctica 3)

h Para terminar un proceso, aunque no es recomendable

TerminateProcess

(ver práctica 3)

h Son los elementos que ejecutan código y sobre los que

actúa el planificador del sistema operativo y los que

usan y comparten recursos

h Ventajas del uso de hilos:

– Posibilidad de uso compartido de recursos dentro del mismo

proceso

– Rapidez en la creación y destrucción de hilos Æ escasa

sobrecarga del sistema

– Ágil conmutación entre los hilos de un mismo proceso

– Aunque un hilo se bloquee (por ejemplo por espera de un datos

del exterior), el resto de sistema puede seguir funcionando

– Posibilidad de dedicar hilos al las tareas de cálculo intensivo, sin

paralizar el resto

– Posibilidad de asignar prioridades a cada hilo

h Gracias a la conmutación entre los hilos, se produce una

ejecución (aparentemente) en paralelo.

(10)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 19

19

Tema 6.2: Programación de Sistemas en Tiempo Real

hPara crear un hilo hacen falta:

– Función punto de entrada, esta función

contiene el código que debe ejecutarse con el

hilo.

DWORD WINAPI NombreFuncionDelThread(

LPVOID PunteroGenerico)

– NombreFuncionDelThread: es el nombre con le que

haremos referencia a la función

– PunteroGenerico: es una variable de tipo LPVOID que

nos permitirá pasarle información a la función del hilo,

nosotros no lo usaremos.

(11)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 21

21

– Ejecutar la función CreateThread. En nuestro caso

siempre usaremos de la siguiente manera:

• Declarar una variable de manejador

• Y llamar a la función:

HANDLE HMiThread; // Declararemos un manejado para el hilo

HMiThread = CreateThread(// Crea un thread

NULL,

// Ignorado en WCE

0,

// Ignorado en WCE

NombreFuncionDelThread,//Nombre del punto de entrada del

thread

NULL,

// Siempre NULL

0, // CREATE_SUSPEND si queremos crearlo suspendido

NULL); // Siempre NULL

#include "stdafx.h" #include <stdio.h>

DWORD WINAPI hilito (LPVOID); static int washere=0;

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)

{

HANDLE mihilo;

printf ("Estoy en el hilo principal\n");

mihilo=CreateThread (NULL, 0, hilito, NULL, 0, NULL); Sleep(2);

if (washere==1)

printf ("Otro hilo diferente al principal ha cambiado al variable global\n");

}

DWORD WINAPI hilito (LPVOID NADA) {

printf ("Estoy en otro hilo diferente al principal\n"); washere=1;

return 0; }

Estoy en el hilo principal

Estoy en otro hilo diferente al principal

Otro hilo diferente al principal ha cambiado al variable global

(12)

Tema 6.2: Programación de Sistemas en Tiempo Real Informática Industrial 3º Ing. Técnico Industrial en Electrónica Industrial 23

23

h Para suspender un hilo, desde el mismo hilo, hay que

llamar a la función:

Sleep(miliseg);

miliseg: tiempo en milisegundos que el hilo estará suspendido

h Para suspender un hilo, desde fuera del hilo, hay que

llamar a la función:

SuspendThread(mihilo

);

mihilo: es el manejador devuelto por CreateThread

h Para reactivar un hilo hay que llamar a la función:

ResumeThread(mihilo

);

mihilo: es el manejador devuelto por CreateThread

Tema 6.2: Programación de Sistemas en Tiempo Real

Hilos: Destrucción y tiempo en ejecución

Hilos: Destrucción y tiempo en ejecución

h Cuando un hilo termina de ejecutar el código de la

función punto de entrada acaba solo, pero se puede

destruir antes.

h Para destruir un hilo hay que llamar a la función:

TerminateThread(mihilo,0

);

• mihilo: es el manejador devuelto por CreateThread

• El segundo parámetros siempre debe ser 0.

h El tiempo mínimo en que un proceso está en ejecución

se llama quantum, por lo general es fijo (en Windows CE

100ms), pero puede cambiarse usando la función:

ceSetThreadQuantum(mihilo,miliseg;

• mihilo: es el manejador devuelto por CreateThread

• miliseg: el nuevo quantum para ese hilo

Referencias

Documento similar

Por primera vez desde 1980 también, los dos partidos de la izquierda abertzale suponen más de la mitad del voto de izquierda (54,5 por 100), incrementándose la fragmentación en

nes de una misma comunidad político-religiosa y, cultural, con muy ligeras diferencias en su zona Central, la mediterránea.' Es cierto que en las regiones montañosas del

Comunicación en los sistemas distribuidos de control en tiempo real .... Sistemas disparados por tiempo y disparados por

However, the elements of the Mueller matrix associated with an optical medium don’t include direct information about the relevant parameters of the physical behavior of the medium,

En línea con los trabajos que se han desan•ollado ya en los años precedentes, el programa contempla el reforzamiento de las redes de alerta sanitaria para evitar cualquier tipo

De este modo, la inscripción del libro en la colección mencionada obliga al primero a aceptar los criterios de espec(ficidad artística que re\plan el campc la segunda. De

Esta asignatura abarca los sistemas en tiempo real aplicadas a entornos industriales, incluyendo la programación en Java y tecnologías para buses de campo y procesamiento

La figura siguiente muestra un nivel de jerarquía múltiple donde un registro DEPARTAMENTO se puede declarar miembro del conjunto DIVIS_DEPART y propietario del conjunto