La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Sebastián Sánchez Prieto

Presentaciones similares


Presentación del tema: "Sebastián Sánchez Prieto"— Transcripción de la presentación:

1 Sebastián Sánchez Prieto
POSIX IEEE 1003 Sebastián Sánchez Prieto

2 Introducción POSIX son un conjunto de normas IEEE/ISO que definen la interfaz entre las aplicaciones y el SSOO POSIX: Portable Operating System Interface + UniX Su objetivo es conseguir la portabilidad de las aplicaciones a nivel de código fuente La aplicación puede desarrollarse en C, Ada, Fortran y otros lenguajes Las normas definen los servicios que cada sistema operativo particular puede incluirlos o no La denominación oficial es IEEE Std. 1003, e ISO/IEC-9945

3 POSIX: estándares base (C)
POSIX 1, 1a Unix básico sin tiempo real POSIX 1b, 1d, 1i, 1j Extensiones de tiempo real POSIX 1c Extensiones de threads POSIX 1e Seguridad POSIX 1f Network File System POSIX 1g Servicios de red (sockets) POSIX 1h Tolerancia a fallos POSIX 21 Comunicaciones de TR

4 POSIX: interfaz otros lenguajes
POSIX 5, 5a, 5b Interfaces con Ada POSIX 9 Interfaces con Fortran 77

5 POSIX: perfiles de entornos
POSIX 10 Supercomputadores POSIX 13 Tiempo real POSIX 14 Multiprocesadores POSIX 18 Estación de trabajo POSIX

6 POSIX de tiempo real ¿para qué?
Existe gran diversidad de sistemas de TR: Núcleos de TR (LynxOS, VxWorks, QNX, etc.) Ejecutivos Ada En sistemas grandes: VMS y otros Era necesario definir un estándar que asegurase la portabilidad de aplicaciones a nivel de código fuente entre diferentes entornos de tiempo real

7 Perfiles de entornos de aplicación
PSE50: sistema de tiempo real mínimo Sólo procesos ligeros, sin gestión de memoria ni archivos ni terminal PSE51: controlador de tiempo real Añade el terminal y sistema de archivos PSE52: sistema de tiempo real dedicado Soporta procesos pesados y gestión de memoria PSE53: sistema de tiempo real generalizado Sistema completo con todos los servicios

8 Características de los perfiles
Sistema de archivos Múltiples procesos Threads Sistema mínimo NO NO Controlador NO Sistema dedicado NO Sistema multipropósito

9 POSIX: Unix básico POSIX 1 define los servicios ofrecidos por Unix:
Gestión de procesos: Creación y destrucción Sincronización Temporización Gestión de archivos Creación y borrado de archivos y directorios Trabajo con archivos especiales Protección de la información Entrada-salida y control

10 POSIX: Extensiones de TR
Para obtener determinismo en el comportamiento Planificación Gestión de memoria Señales Relojes y temporizadores Para facilitar la concurrencia Sincronización Memoria compartida Colas de mensajes Entrada-salida síncrona y asíncrona

11 POSIX: Extensiones de threads
POSIX 1c incorpora funciones para trabajar con hilos. Incluye: Gestión de hilos Sincronización de hilos Planificación de hilos Creación y destrucción de hilos Añade reentrada a algunas funciones de POSIX1 POSIX 1c puede hacer uso de funciones incluidas en POSIX 1 y POSIX 1b

12 POSIX: Procesos y planificación

13 Definiciones Programa
Archivo ejecutable residente en un dispositivo de almacenamiento permanente Se ejecuta por medio de la llamada exec() Proceso Es un programa en ejecución Los procesos se crean con la llamada fork() Servicios del sistema operativo Invocados por medio de funciones POSIX no diferencia entre llamadas al sistema y procedimientos de biblioteca

14 Estructura de un proceso en C
Proceso de usuario Funciones main() Rutina de inicio exit() _exit() exec() Llamada al sistema Núcleo

15 Ejemplo /**************************************
* Programa que imprime todos los * * argumentos de línea de órdenes * **************************************/ int main (int argc, char *argv[]) { int i; for (i=0; i<argc; i++) printf (“%s\n”, argv[i]); exit(0); } /* Fin de main */

16 Características de un proceso
Cada proceso se caracteriza por una estructura de datos conocida como tabla de control de tarea que contiene: Identificador de proceso o PID Identificador de proceso padre o PPID Identificador de usuario o UID Identificador de grupo o GID Puntero a la memoria asignada Puntero a los recursos ... Cada proceso dispone de un espacio de direccionamiento virtual independiente

17 Creación de procesos: fork()
La llamada fork() crea una copia (hijo) del proceso que la invoca El hijo hereda del padre: Estado Semáforos Objetos de memoria Política de planificación, etc. El hijo no hereda: El PID Alarmas y temporizadores Operaciones de E/S asíncronas

18 Interfaz de fork() Definida en: Valores de retorno:
#include <sys/types.h> pid_t fork(void); Valores de retorno: Al padre: el PID del hijo Al hijo: cero En caso de error: devuelve -1 y la variable errno contiene el valor asociado al error

19 Ejemplo con fork() #include <sys/types.h> int main(void) {
pid_t id; id = fork(); if (id == -1) { perror (“Error en el fork”); exit (1); } if (id == 0) { while (1) printf (“Hola: soy el hijo\n”); } else { while (1) printf (“Hola: soy el padre\n”); } /* Fin de main */

20 Ejecución de programas: exec()
La familia de llamadas exec() se emplea para cargar la imagen de un proceso desde un archivo a memoria La nueva imagen se carga encima de la del proceso que invoca la llamada, machacándolo El nuevo proceso hereda: El PID y el PPID del proceso original La política de planificación Las alarmas y señales pendientes

21 Prototipos de la familia exec()
Definidos en: #include <unistd.h> int execl (const char *path, const char *arg, ...); int execlp (const char *file, int execle (const char *path, const char *arg, ..., char * const envp[]); int execv (const char *path, char const *argv[]); int execvp (const char *file, char const *argv[]); Valores de retorno: En caso de error exec() devuelve -1

22 Ejemplo con exec() #include <unistd.h> int main(void) { int ret;
char *arg[3]; arg[0] = “ls”; arg[1] = “-l”; arg[2] = (char *)0; printf (“Allá va!\n”); ret = execv (“/bin/ls”, arg); if (ret == -1) { perror (“Error en el exec”); exit (1); } } /* Fin de main */

23 Finalización de procesos: exit()
La llamada exit() provoca la finalización del proceso que la invoca Esta llamada nunca retorna Cuando un proceso termina, sus hijos no mueren y suelen ser adoptados por el proceso init Prototipo definido en: #include <unistd.h> void _exit (int status); El valor status es retornado al padre si es que existe

24 Espera por procesos: wait()
La llamada wait() permite que un proceso quede esperando a que sus hijos terminen El padre puede conocer el valor de retorno de cada hijo Prototipos definido en: #include <sys/types.h> #include <sys/wait.h> pid_t wait (int *status); pid_t waitpid(pid_t pid, int *status, int options);

25 Ejemplo con wait() #include <sys/types.h>
#include <sys/wait.h> int main(void) { pid_t id; int estado; id = fork(); if (id == -1) { perror (“Error en el fork”); exit (1); }

26 Continuación del ejemplo
if (id == 0) { printf (“Soy el hijo\n”); sleep(3); printf (“Hijo: despierta y finaliza\n”); exit(0); } else { printf (“Soy el padre y ahora espero ...\n”); wait (&estado); printf (“Padre: el hijo terminó con estado = %d\n”, estado); exit (0); } } /* Fin de main */

27 Planificación Los mecanismos clásicos de planificación no son válidos
Es necesario evitar el indeterminismo POSIX 1b utiliza una planificación expulsora con prioridades fijas (32 como mínimo) con tres políticas diferentes: SCHED_FIFO FIFO para tareas de igual prioridad SCHED_RR Round-Robin en tareas con la misma prioridad. El quanto es fijo SCHED_OTHER Definido por la realización concreta

28 Planificación (continuación)
Los parámetros de planificación y los prototipos de las funciones se encuentran en: #include <sched.h> Parámetros de planificación: struct sched_param { int sched_priority; } Definir política y parámetros (hay que ser root): int sched_setscheduler (pid_t pid,int policy, const struct sched_param *param);

29 Planificación (continuación)
Leer la política y los parámetros: int sched_getscheduler (pid_t pid); int sched_getparam (pid_t pid, struct sched_param *param); Ceder el procesador: int sched_yield (void); Leer los límites de los parámetros: int sched_get_priority_max (int policy); int sched_get_priority_min (int policy); int sched_rr_get_interval (pid_t pid, struct timespec *interval);

30 Ejemplo #include <sched.h> #include <sys/types.h>
int main(void) { pid_t pid; struct sched_param parametros; int i, max_prio; pid = getpid(); max_prio = sched_get_priority_max(SCHED_FIFO); parametros.sched_priority = max_prio; sched_setscheduler(pid, SCHED_FIFO, &parametros); for (i=0; i< ; i++); } /* Fin de main */

31 POSIX: Gestión de memoria

32 Introducción La memoria virtual introduce NO determinismo
POSIX proporciona la posibilidad de bloquear memoria para evitar la aleatoriedad Los procesos a pesar de tener un espacio de direccionamiento disjunto pueden compartir objetos de memoria La compartición se realiza mapeando la zona de memoria que deseamos compartir en los espacios de direccionamiento virtuales de cada proceso La compartición se realiza a través de páginas de modo que el tamaño de una zona proyectada es un múltiplo del tamaño de la página

33 Bloqueo de memoria Los procesos pueden bloquear todas sus páginas en memoria para evitar el intercambio con el disco #include <sys/mman.h> int mlockall (int flags); El valor de flags puede ser: MCL_CURRENT: afecta a las páginas actuales MCL_FUTURE: afecta a las páginas futuras Para liberar todas las páginas del proceso: int munlockall (void);

34 Bloqueo de memoria Un proceso pueden bloquear también un rango de su espacio de direccionamiento int mlock (const void *addr, size_t len); Para desbloquear un rango de direcciones: int munlock (const void *addr, size_t len);

35 Memoria compartida Proceso 1 Proceso 2 Memoria física M. Compartida

36 Proyección de objetos en memoria
La llamada mmap() permite proyectar objetos en memoria Estos objetos pueden ser compartidos Función mmap(): void *mmap (void *addr, size_t len, int prot, int flags, int fildes, off_t off); El objeto queda identificado por fildes len y off son la longitud y el offset del objeto en bytes respectivamente addr es la dirección donde deseamos proyectar el objeto preferiblemente. Es sólo una indicación

37 Proyección de objetos en memoria
La dirección real donde se proyecta el objeto es devuelta por mmap()y depende del valor de flags: MAP_FIXED: addr se interpreta de forma exacta, sin este flag si addr vale NULL, el sistema elige la dirección MAP_SHARED: los cambios son compartidos MAP_PRIVATE: no se comparten los cambios prot especifica el tipo de acceso: PROT_READ: derecho de lectura PROT_WRITE: derecho de escritura PROT_EXEC: derecho de ejecución PROT_NONE: sin derechos

38 Proyección de objetos en memoria
Para eliminar la proyección de un objeto en memoria emplearemos la función munmap() int munmap (void *addr, size_t len);

39 Objetos de memoria compartida
Para abrir un objeto de memoria compartida: #include <sys/mman.h> int shm_open (const char *path, int oflag, mode_t mode ); Se establece una conexión entre el path que identifica al objeto y el descriptor devuelto oflag determina el modo de acceso mode determina los derechos de acceso si creamos un nuevo objeto Es recomendable por razones de portabilidad que el path comience con el carácter /

40 Objetos de memoria compartida
Fijar el tamaño de un objeto de memoria compartida int ftruncate (int fildes, off_t length); Para borrar un objeto de memoria compartida: int shm_unlink (const char *path);

41 POSIX: Relojes y temporizadores

42 Introducción El reloj sirve para medir el paso del tiempo Tick:
Unidad del tiempo El número de ticks por segundo se puede conocer con sysconf (_SC_CLK_TCK) Resolución: Mínimo intervalo de tiempo que un reloj puede medir La Época: CUT (Coordinated Universal Time) 0 h 0 m 0s del 1 de enero de 1970

43 Introducción Temporizador
Es un objeto que puede avisar a los procesos si ha transcurrido cierta cantidad de tiempo o se ha alcanzado cierta hora Cada temporizador está asociado a un reloj Reloj del sistema Mide los segundos desde La Época Mantiene la hora Reloj de tiempo real Se usa para timeouts y temporizadores

44 Reloj del sistema Leer la hora:
#include <time.h> time_t time (time_t *t); time() devuelve los segundos transcurridos desde La Época Si t es distinto de NULL en él se devuelve la hora también Alarma: #include <unistd.h> unsigned int alarm (unsigned int seconds); Cuando transcurren los segundos especificados se envía la señal SIGALRM

45 Ejemplo #include <signal.h> #include <stdio.h>
#include <unistd.h> #include <time.h> void manejador (int senal) { time_t seg; printf (“Recibida la señal de alarma ... \n”); seg = time (NULL); printf (“Segundos desde La Época: %d\n”, seg); exit (0); }

46 Ejemplo (continuación)
main() { struct sigaction accion; time_t seg; accion.sa_flags = 0; accion.sa_handler = manejador; sigemptyset (&accion.sa_mask); sigaction (SIGALRM, &accion, NULL); seg = time (NULL); printf (“Segundos desde La Época: %d\n”, seg); alarm (3); while (1); } /* Fin de main */

47 Reloj de tiempo real La estructura timespec:
typedef struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ } timespec_t; Tiempo = tv_sec * tv_nsec

48 Manejo de relojes Cambio de hora: Obtención de la hora:
#include <time.h> int clock_settime(clockid_t clock_id, const struct timespec *tp); Obtención de la hora: int clock_gettime(clockid_t clock_id, struct timespec *tp); Resolución del reloj: int clock_getres(clockid_t clock_id, struct timespec *res); clockid_t debe valer CLOCK_REALTIME para TR

49 Ejemplo #include <time.h> main() { struct timespec stime;
clock_getres (CLOCK_REALTIME, &stime); printf (“Segundos: %d\n”, stime.tv_sec); printf (“Nanosegundos: %ld\n”, stime.tv_nsec); } /* Fin de main */

50 Temporizadores Se utilizan para generar señales en ciertos momentos o para ejecutar acciones periódicas ¿Cómo crear un temporizador? #include <signal.h> #include <time.h> timer_create(clockid_t clock_id,struct sigevent *evp, timer_t *timerid); sigevent indica el modo de aviso: ninguno, señal o crear y ejecutar un hilo timerid es el identificador devuelto El temporizador inicialmente no está activo

51 Temporizadores ¿Cómo borrar un temporizador?
timer_delete (timer_t timerid); ¿Cómo activar un temporizador? int timer_settime (timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); Estructura itimerspec: it_interval: periodo it_value: tiempo de expiración Si it_value vale 0 el temporizador es desactivado Si it_value > 0 el temporizador se activa en el instante especificado

52 Temporizadores Si el temporizador ya estaba activado, se reactiva
flag indica si el temporizador es absoluto o relativo Si flag = TIMER_ABSTIME, la primera expiración será cuando el reloj valga it_value Si no se especifica nada, se espera hasta empezar el tiempo definido en it_value ¿Cómo leer el valor de un temporizador? int timer_gettime (timer_t timerid, struct itimerspec *value);

53 Ejemplo #include <time.h> #include <signal.h>
void manejador(int senal) { struct timespec stime; clock_gettime (CLOCK_REALTIME, &stime); printf (“Repeticion -> Segundos: %d\t”, stime.tv_sec); printf (“Nanosegundos: %ld\n”, stime.tv_nsec); } /* Fin de manejador */

54 Ejemplo main() { struct sigaction accion; struct sigevent evento;
timer_t idtemp; struct itimerspec itspec; struct timespec stime; accion.sa_flags = 0; accion.sa_handler = manejador; sigemptyset (&accion.sa_mask); sigaction (SIGUSR1, &accion, NULL); evento.sigev_signo = SIGUSR1; evento.sigev_notify = SIGEV_SIGNAL;

55 Ejemplo timer_create(CLOCK_REALTIME, &evento,&idtemp);
itspec.it_value.tv_sec=5;/*Activación en 5 s*/ itspec.it_value.tv_nsec = 0; itspec.it_interval.tv_sec = 1; itspec.it_interval.tv_nsec = 0; timer_settime (idtemp, 0, &itspec, NULL); clock_gettime (CLOCK_REALTIME, &stime); printf (“Comienzo -> Segundos: %d\t”, stime.tv_sec); printf (“Nanosegundos: %ld\n”, stime.tv_nsec); while(1); } /* Fin de main */

56 Ejecución Comienzo -> Segundos: 921550145 Nanosegundos: 828803000
Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos: Repetición -> Segundos: Nanosegundos:

57 sleep() Se emplea para dormir a un proceso o a un hilo hasta que transcurran lo segundos especificados unsigned int sleep (unsigned int seconds); Existe un sleep() de alta resolución int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); Con nanosleep() se duerme hasta que transcurre el intervalo especificado o hasta que se recibe una señal rqtp es el tiempo que vamos a dormir rmtp es el tiempo que falta por dormir si se retorna por la activación de una señal

58 POSIX: Sincronización

59 Semáforos Es un tipo de dato protegido que se utiliza para acceso exclusivo a recursos compartidos y para sincronización Introducido por Dijkstra a mediados de los 60 Si su valor es cero, el semáforo no está disponible Si su valor es positivo, está disponible Operaciones sobre semáforos: P (semáforo); V (semáforo); Existen semáforos con y sin nombre

60 Funciones asociadas Iniciar un semáforo sin nombre:
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); sem identifica al semáforo pshared determina si sólo puede ser utilizado por hilos del mismo proceso (=0) o se puede compartir entre procesos (!=0) value es el valor inicial del semáforo Destruir un semáforo sin nombre int sem_destroy(sem_t *sem);

61 Funciones asociadas Iniciar un semáforo con nombre:
sem_t *sem_open (const char *name, int oflag, ... /* mode_t mode, int value */); La función devuelve un puntero al semáforo name debe tener el formato “/name” oflag indica las opciones O_CREAT: si el semáforo no existe, se crea. En este caso se requieren los permisos de acceso (mode) y el valor inicial (value) O_EXCL: si el semáforo existe se produce un error Cerrar un semáforo con nombre int sem_close(sem_t *sem);

62 Funciones asociadas Borrar un semáforo con nombre: Operación P:
int sem_unlink (const char *name); Operación P: int sem_wait(sem_t *sem); Si el semáforo está libre, lo toma, en caso contrario, el proceso se bloquea Operación P (con consulta): int sem_trywait(sem_t *sem); Toma el semáforo si está libre, en caso contrario devuelve error

63 Funciones asociadas Operación V (liberar un semáforo):
int sem_post (sem_t *sem); Leer el valor de un semáforo: int sem_getvalue(sem_t *sem, int *sval);

64 Ejemplo #include <semaphore.h> #include <sys/types.h>
#define SEM “/usr/people/chan/src/semaforo” main() { sem_t *sem; pid_t id; int i; sem = sem_open (SEM, O_CREAT, 666, 0); if ((int)sem == -1) { perror (“Error en sem_open”); } id = fork(); if (id == -1) { perror (“Error en el fork”);

65 Ejemplo exit (1); } if (id == 0) { for (i=1; i<20; i++) {
printf (“Hijo %d\n”, i); sem_post (sem); sleep (1); } else { sem_wait (sem); printf (“Padre %d\n”, i); } /* Fin de main */

66 POSIX: Mensajes

67 Definición Es una información que se transfiere entre diferentes procesos o hilos mediante su inserción o extracción de una cola de mensajes Cada mensaje lleva asociada una prioridad Los mensajes se extraen de la cola de mensajes por orden de prioridad (no FIFO) Las colas de mensajes se identifican por medio de un nombre o un descriptor de cola de mensajes El envío de los mensajes puede ser bloqueante o no bloqueante en función de si el buffer está lleno o vacío

68 Atributos de las colas Estructura mq_attr
Está declarada en <mqueue.h> typedef struct mq_attr { long mq_flags; /*O_NONBLOCK -> no bloqueante*/ long mq_maxmsg; /*número máximo de mensajes*/ long mq_msgsize; /*tamaño máximo del mensaje*/ long mq_curmsgs; /*actual número de mensajes*/ } mq_attr_t;

69 Funciones asociadas Abrir una cola de mensajes:
mqd_t mq_open (const char *mq_name, int oflag, /* mode_t mode, struct mq_attr *mq_attr */); La función devuelve un descriptor de cola mq_name debe ser del tipo “/name” oflag indica el modo de apertura Con O_CREAT mode especifica los derechos y mq_attr los atributos de creación

70 Funciones asociadas Cerrar una cola de mensajes:
mqd_t mq_close (mqd_t mqd); Borrar una cola de mensajes: int mq_unlink (const char *mq_name); Definir los atributos de una cola: int mq_setattr (mqd_t mqd, struct mq_attr *mqstat, struct mq_attr *omqstat); Obtener los atributos de una cola: int mq_getattr (mqd_t mqd, struct mq_attr *mqstat);

71 Funciones asociadas Enviar un mensaje:
int mq_send (mqd_t mqd, const char *msgptr, size_t msglen, unsigned int msg_prio); *msgptr es el puntero al mensaje msglen es su longitud msg_prio es la prioridad del mensaje Recibir un mensaje: int mq_receive (mqd_t mqd, char *msgptr, size_t msglen, unsigned int *msgprio);

72 Funciones asociadas Avisar de la llegada de un mensaje:
int mq_notify (mqd_t mqd, const struct sigevent *notification); cuando llega el mensaje se avisa al proceso del evento sólo se puede avisar a un proceso si el proceso está esperando con mq_receive, la notificación no se produce

73 Ejemplo #include <mqueue.h> #include <fcntl.h>
#include <sys/types.h> #define MQ “/usr/people/chan/src/mesgq” main() { struct mq_attr qattr; mqd_t qfd; pid_t id; int i; unsigned int Prio; char Mensaje[20];

74 Ejemplo qattr.mq_maxmsg = 32; qattr.mq_msgsize = 20;
qfd = mq_open (MQ, O_CREAT|O_RDWR, 666, &qattr); if (qfd == -1) { perror (“Error en mq_open”); } id = fork(); if (id == -1) { perror ("Error en el fork"); exit (1);

75 Ejemplo if (id == 0) { for (i=1; i<20; i++) {
printf (“Hijo %d\n”, i); mq_send (qfd, “Hola”, 5, 1); sleep (1); } } else { mq_receive (qfd, Mensaje, sizeof (Mensaje), &Prio); printf (“Padre %d - Mensaje %s\n”, i, Mensaje); } /* Fin de main */

76 POSIX 1c: Threads

77 Introducción Un thread es un flujo de control perteneciente a un proceso (a veces se habla de tareas con threads) Se les suele denominar también procesos ligeros, hebras, hilos, etc. La sobrecarga debida a su creación y comunicación es menor que en los procesos pesados Cada hilo pertenece a un proceso pesado Todos los hilos comparten su espacio de direccionamiento Cada hilo dispone de su propia política de planificación, pila y contador de programa

78 Introducción Sistema Operativo Hardware
Cada hilo tiene su propio identificador tid que sólo es válido para hilos del mismo proceso Una aplicación con hilos puede beneficiarse de un procesamiento paralelo real en sistemas multiprocesador Hilos Procesos pesados Sistema Operativo Hardware

79 Operaciones con hilos Creación y destrucción Sincronización
Gestión de prioridades Gestión de señales Gestión de memoria Se pueden utilizar todas las funciones incluidas en POSIX.1 y POSIX.1b La interfaz de hilos POSIX es pthreads, aunque existen otras bibliotecas de hilos

80 Operaciones asociadas
Crear un nuevo hilo: int pthread_create (pthread_t *thread, pthread_attr_t *attr, void *(*start)(void *), void *arg); En thread devuelve el identificador de hilo attr es un puntero a los atributos de la tarea El tercer argumento en un puntero a la función que ejecutará el hilo arg es un puntero a los argumentos del hilo Finalizar un hilo: void pthread_exit(void *retval);

81 Ejemplo #include <pthread.h> void *Hilo (void *arg) {
printf (“%s\n”, (char *)arg); pthread_exit (0); } /* Fin de Hilo */ main() { pthread_t th1, th2; pthread_create (&th1, NULL, Hilo, “Hilo 1”); pthread_create (&th2, NULL, Hilo, “Hilo 2”); sleep(5); puts (“Adios: Hilo principal”); } /* Fin de main */

82 Atributos de los threads
Los atributos definibles son: Tamaño de la pila Dirección de la pila Control de devolución de recursos Los atributos se crean con: int pthread_attr_init(pthread_attr_t *attr); Los atributos se destruyen con: int pthread_attr_destroy(pthread_attr_t *attr);

83 Definición y obtención de attr
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size); int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size); int pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr); int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr); int thread_attr_setdetachstate(pthread_attr_t *attr, int detach); int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detach);

84 Devolución de recursos
Los hilos pueden operar en dos modos diferentes para controlar la devolución de recursos: Detached: opera de modo autónomo, cuando termina devuelve sus recursos (identificador, pila, etc.) Joinable: en su terminación mantiene sus recursos hasta que otro hilo invoca a pthread_join()

85 Devolución de recursos
Los recursos de una tarea joinable se liberan cuando esperamos con pthread_join() int pthread_join(pthread_t thread, void **retval); Si la tarea opera en modo detached, el propio hilo al terminar libera sus recursos. Para convertir a un hilo en detached, si no se hizo en su inicio: int pthread_detach(pthread_t thread);

86 Ejemplo #include <pthread.h> void *Hilo (void *arg) {
printf (“%s\n”, (char *)arg); sleep(3); pthread_exit (NULL); } /* Fin de Hilo */ main() { pthread_t th1, th2; void *st1; pthread_create (&th1, NULL, Hilo, "Hilo 1"); pthread_join (th1, (void **) &st1); printf (“Retorno del hilo: %d\n”, st1); } /* Fin de main */

87 Identificación ¿Cómo obtener el identificador del hilo?
pthread_t pthread_self(void); ¿Cómo comparar identificadores de hilo? int pthread_equal(pthread_t thread1, pthread_t thread2); Si los identificadores coinciden retorna TRUE, en caso contrario, FALSE

88 Cancelación En cualquier momento se puede solicitar la cancelación de un hilo Cuando se solicita la cancelación de un hilo se puede: Finalizar automáticamente el hilo Ignorar la petición y continuar Retrasar la finalización hasta llegar a un punto seguro

89 Funciones asociadas Solicitar la cancelación de un hilo:
int pthread_cancel(pthread_t thread); Habilitar o inhabilitar la cancelación: int pthread_setcancelstate(int new_state, int *old_state); PTHREAD_CANCEL_ENABLE o PTHREAD_CANCEL_DISABLE Establecer el tipo de cancelación: int pthread_setcanceltype(int new_type, int *old_type); PTHREAD_CANCEL_ASYNCHRONOUS o PTHREAD_CANCEL_DEFERRED Verificar y terminar si se ha solicitado la cancelación: void pthread_testcancel(void);

90 Ejemplo #include <pthread.h> void *Hilo (void *arg) { while(1) {
printf (“%s\n”, (char *)arg); sleep(1); } } /* Fin de Hilo */ main() { pthread_t th1; pthread_create (&th1, NULL, Hilo, “Hilo 1”); sleep(5); pthread_cancel(th1); printf(“Envío cancel al Hilo 1 ...\n”); } /* Fin de main */

91 Terminación Se puede instalar manejadores de terminación de hilos
Cuando el hilo termina voluntariamente o por una cancelación, automáticamente se invoca a la función de terminación especificada Esta posibilidad evita el problema de dejar al sistema en un estado inconsistente

92 Funciones asociadas Para instalar un manejador de terminación:
void pthread_cleanup_push(void *(*cleanup)(void *), void *arg); Para eliminar el último manejador instalado: void pthread_cleanup_pop(int exec); Si exec!=0, la función se elimina y se ejecuta

93 Planificación

94 Planificación de threads
Existen las mismas políticas que para los procesos Los atributos de planificación se pueden especificar al crear el hilo en el objeto de atributos Se puede seleccionar entre dos ámbitos de planificación: Ámbito de proceso: un planificador de segundo nivel planifica los hilos de cada proceso PTHREAD_SCOPE_PROCESS Ámbito de sistema: los hilos se planifican como los procesos pesados PTHREAD_SCOPE_SYSTEM

95 Ámbitos (contentionscope)
Hilos Planificador Sistema Operativo Planificador

96 Herencia Si existe herencia no se hace caso del resto de los atributos de planificación Valores: PTHREAD_INHERIT_SCHED: hereda los atributos del padre PTHREAD_EXPLICIT_SCHED: utiliza los del objeto attr

97 Funciones asociadas Definición y obtención del ámbito de contención:
int pthread_attr_setscope(pthread_attr_t *attr, int scope); int pthread_attr_getscope(const pthread_attr_t *attr, int *scope); Definición y obtención de valores de herencia: int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit); int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);

98 Funciones asociadas Definición y obtención de los valores de la política de planificación: int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); Definición y obtención de la prioridad: int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param); int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

99 Cambio dinámico de parámetros
Se puede modificar dinámicamente la política de planificación y la prioridad: int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);

100 Señales

101 Introducción Una señal es un mecanismo para avisar a los proceso de la llegada de un evento División por cero Desbordamiento Expiración de alarmas Llegada de un mensaje etc. Cada señal es identificada por un número Cuando llega una señal, el proceso es interrumpido y se invoca a un manejador de señal

102 Señales ordinarias Las señales no son fiables, se pueden perder si existen señales del mismo número pendientes SIGILL Instrucción ilegal SIGFPE Operación aritmética errónea SIGSEGV Acceso a memoria erróneo SIGINT Señal de atención interactiva (Ctrl-c) SIGPIPE Escritura en una tubería sin lectores SIGSTOP Detiene al proceso SIGCONT Reanuda el proceso SIGUSR1 Reservada para el usuario SIGUSR2 Reservada para el usuario

103 Señales de tiempo real Las señales de tiempo real, si son soportadas, existen con números comprendidos entre SIGRTMIN y SIGRTMAX Las señales de tiempo real son fiables y: No se pierden nunca (se encolan) Se aceptan en orden de prioridad (número) Pueden transmitir un poco de información, un entero o un puntero Existen como mínimo 8

104 Generación, entrega y aceptación
Un señal se genera: Cuando se produce el evento asociado Una señal se entrega Cuando la señal causa al proceso la acción asociada La acción se determina en recepción Una señal se acepta: Al seleccionarla Para aceptar una señal esta debe estar enmascarada

105 Generación, entrega y aceptación
Señal pendiente: Estado entre su generación y su entrega o aceptación Observable si la señal está enmascarada Si se produce el mismo evento asociado a una señal pendiente: Si es una señal no fiable, el evento se puede perder Si es una señal fiable, y se ha especificado la acción SA_SIGINFO, la señal se encola Cada hilo puede tener su máscara La máscara es heredada y se puede modificar

106 Acciones asociadas a señales
Antes de que llegue una señal el proceso puede prepararse para recibirla y actuar El tratamiento de la señal puede implicar: Ignorar la señal (SIG_IGN) Dejar que el sistema la trate por defecto (SIG_DFL) Manejarla con una función específica: cuando se entrega la señal se ejecuta el manejador indicado y se continúa la ejecución en el punto donde fuimos interrumpidos

107 Manejadores de señal POSIX define dos tipos de manejador:
Si se especifica SA_SIGINFO void manejador (int signo); Si no se especifica SA_SIGINFO void manejador (int signo, siginfo_t *info, void *context); La estructura siginfo_t mantiene, entre otras cosas, el número de señal (si_signo) y la causa (si_code)

108 Señales en procesos multihilo
Las señales pueden enviarse a procesos a a hilos Si el evento está asociado a un hilo, la señal es enviada al hilo correspondiente Si el evento es asíncrono, se envía al proceso Las señales asociadas a un PID se envían al proceso y las asociadas a un TID se envían a un hilo

109 Señales en procesos multihilo
Una señal asociada a un hilo: Si no está bloqueada, se entrega Si está bloqueada y la acción no es ignorar se queda pendiente hasta que es desbloqueada o aceptada con sigwait() Si está bloqueada y la acción es ignorar: no está especificado

110 Señales en procesos multihilo
Una señal asociada a un proceso: Si la acción no es ignorar, se envía a un único hilo que esté esperando con sigwait() o a un hilo que no tenga la señal bloqueada Si no es entregada, la señal queda pendiente hasta que un hilo llama a sigwait(), un hilo desbloquea la señal o la acción asociada se pone en ignorar

111 Funciones de configuración
Prototipos definidos en: #include <signal.h> Funciones: int sigaddset(sigset_t *set, int sig); int sigdelset(sigset_t *set, int sig); int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigismember(sigset_t *set, int sig); Todas ellas permiten manipular la máscara de señales apuntada por set

112 Funciones de tratamiento
Para examinar y cambiar la acción asociada a una señal: int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact); Si act=NULL, la acción no se modifica Si oldact!=NULL la acción actual se devuelve en *oldact

113 Estructura sigaction struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); } El primer campo es el puntero al manejador o también SIG_DFL o SIG_IGN El segundo campo es la máscara de señales para cuando estamos tratando la actual

114 Estructura sigaction El tercer campo puede valer:
SA_SIGINFO: La señal se encola y lleva información adicional (el manejador de señal es de tres argumentos) SA_NOCLDSTOP: no generar SIGCHLD cuando un hijo se detiene El cuarto campo es el puntero a la función que se ejecutará si esta definido el flag SA_SIGINFO

115 Bloqueo de señales Para examinar y cambiar las señales bloqueadas:
int sigprocmask (int operation, cont sigset_t *set, sigset_t *oldset); /* un único hilo */ int pthread_sigmask(int operation, const sigset_t *set, sigset_t *old_set); operation indica el modo de operar: SIG_BLOCK: añade señales bloqueadas SIG_UBLOCK: elimina señales bloqueadas SIG_SETMASK: modifica toda la mascara de señales set: señales afectadas. Si vale NULL, no se cambia ninguna oldset: si !=NULL, devuelve las señales bloqueadas anteriormente

116 Envío de señales Para enviar señales a procesos:
int kill (pid_t pit, int sig); int sigqueue (pid_t victim_id, int this_sig, union sigval extra_info); Para enviar señales a hilos: int pthread_kill(pthread_t thread, int sig);

117 Aceptación de señales Para examinar señales pendientes:
int sigpending (sigset_t *set); Para esperar a que se ejecute un manejador de señal: int pause(void); int sigsuspend (const sigset_t *mask); sigsuspend() sustituye la máscara de señales con la apuntada por mask y espera la recepción de una de ellas. Al retornar se restaura la máscara original

118 Aceptación de señales Esperar a una señal bloqueada:
int sigwait(const sigset_t *set, int *sig); int sigwaitinfo(const sigset_t *set, siginfo_t *value); int sigtimedwait(const sigset_t *set, siginfo_t *value, timespec_t *timeout);

119 Ejemplo #include <signal.h> #include <stdio.h>
void manejador (int senal) { printf (“Recibida la señal ... \n”); } main() { struct sigaction accion; accion.sa_flags = 0; accion.sa_handler = manejador; sigemptyset (&accion.sa_mask); sigaction (SIGUSR1, &accion, NULL); while (1); } /* Fin de main */

120 Sincronización

121 Mutex Es un objeto de sincronización que permite el acceso exclusivo a recursos Operaciones: P() V() Soportan herencia de prioridad

122 Objeto de atributos Atributos de inicio:
pshared: compartido o no entre procesos PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_PRIVATE protocol: protocolo utilizado PTHREAD_PRIO_NONE: sin herencia PTHREAD_PRIO_INHERIT: con herencia PTHREAD_PRIO_PROTECT: protección de prioridad prioceiling: techo de prioridad Estos atributos se almacenan en el objeto de atributos

123 Funciones de manipulación
int pthread_mutexattr_init(pthread_mutexattr_t *attr); int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol); int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr, int prioceiling); int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling);

124 Manejo de mutex int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr); int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_destroy(pthread_mutex_t *mutex);

125 Cambio del techo de prioridad
int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling); int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling);

126 Variables de condición
Es un objeto de sincronización que permite bloquear a un hilo hasta que otro decide reactivarlo Operaciones: Esperar una condición: un hilo se suspende hasta que otro señaliza la condición. En este punto se comprueba la condición y el proceso se repite si la condición es falsa Señalizar una condición: se avisa a uno o más hilos suspendidos broadcast: se reactivan todos los hilos suspendidos en la condición

127 Atributos pshared: indica si se puede compartir entre procesos
PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_PRIVATE Funciones: int pthread_condattr_init(pthread_condattr_t *attr); int pthread_condattr_destroy(pthread_condattr_t *attr);

128 Funciones asociadas int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *attr); int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

129 Referencias Michael González Harbour: POSIX de Tiempo Real Curso de doctorado Ismael Ripoll. POSIX Curso de doctorado Juan Antonio de la Puente. Curso de doctorado Programming for the Real World. POSIX.4. Bill o. Gallmeister. O´Reilly. 1995 Pthreads Programming. Bradford Nichols. O’Reilly. 1996


Descargar ppt "Sebastián Sánchez Prieto"

Presentaciones similares


Anuncios Google