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
Funciones asociadas Iniciar un semáforo sin nombre: #include 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);
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);
Funciones asociadas Borrar un semáforo con nombre: 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
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);
Ejemplo #include #include #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”);
Ejemplo exit (1); } if (id == 0) { for (i=1; i<20; i++) { printf (“Hijo %dn”, i); sem_post (sem); sleep (1); } } else { for (i=1; i<20; i++) { sem_wait (sem); printf (“Padre %dn”, i); } } } /* Fin de main */
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
Atributos de las colas Estructura mq_attr Está declarada en 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;
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
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);
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);
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
Ejemplo #include #include #include #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];
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); }
Ejemplo if (id == 0) { for (i=1; i<20; i++) { printf (“Hijo %dn”, i); mq_send (qfd, “Hola”, 5, 1); sleep (1); } } else { for (i=1; i<20; i++) { mq_receive (qfd, Mensaje, sizeof (Mensaje), &Prio); printf (“Padre %d – Mensaje %sn”, i, Mensaje); }
} } /* Fin de main */
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
Introducción 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
Sistema Operativo Hardware Procesos pesados Hilos
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
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);
Ejemplo #include void *Hilo (void *arg) { printf (“%sn”, (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 */
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);
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);
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()
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);
Ejemplo #include void *Hilo (void *arg) { printf (“%sn”, (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: %dn”, st1); } /* Fin de main */
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
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
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);
Ejemplo #include void *Hilo (void *arg) { while(1) { printf (“%sn”, (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”); sleep(5); } /* Fin de main */
Página anterior | Volver al principio del trabajo | Página siguiente |