Programación Concurrente Ejemplos Jesús Sanz Marcos e-mail: [email protected] Barcelona, Spain. 02/01/2001 Productores-Consumidores (Monitores) typedef struct { queue q; pthread_cond_t notfull,notempty; pthread_mutex_t m; } Buffer; void Buffer_Init(Buffer * t) { pthread_mutex_init(&b->m,NULL); pthread_cond_init(&b->notfull,NULL); pthread_cond_init(&b->notempty,NULL); } void Buffer_Done(Buffer *t) { pthread_mutex_destroy(b->m); pthread_cond_destroy(b->notfull); pthread_cond_destroy(b->notempty); } void Buffer_Put(buffer *b, packet p) { pthread_mutex_lock(&b->m); while (IsFullQueue(&b->q)) pthread_cond_wait(&b->notfull,&b->m); PutQueue(&b->q, p); pthread_mutex_signal(&b->notempty); pthread_mutex_unlock(&b->m); } packet Buffer_Get(buffer *b) { packet p; pthread_mutex_lock(&b->m); while (IsEmptyQueue(&b->q)) pthread_cond_wait(&b->notempty,&b->m); p = GetQueue(&b->q); pthread_mutex_signal(&b->notfull); pthread_mutex_unlock(&b->m); return p; } Lectores/Escritores (Monitores) typedef struct { int readers; int writing; pthread_cond_t oktoread,oktowrite; pthread_mutex_t m; } Table; void Table_Init(Table * t) { pthread_mutex_init(&t->m,NULL); pthread_cond_init(&t->oktoread,NULL); pthread_cond_init(&t->oktowrite,NULL); readers = 0; writting = FALSE; } void Table_Done(Table *t) { pthread_mutex_destroy(t->m); pthread_cond_destroy(t->oktoread); pthread_cond_destroy(t->oktowrite); } void Table_StartRead(Table *t) { pthread_mutex_lock(&t->m); if (t->writting || !pthread_cond_empty(&t->oktowrite)) pthread_cond_wait(&t->oktoread, &t->m); t->readers++; pthread_mutex_unlock(&t->m); } void Tabla_EndRead(Table *t) { pthread_mutex_lock(&t->m); t->readers--; if (t->readers==0) pthread_cond_signal(&t->oktowrite); pthread_mutex_unlock(&t->m); } void Table_StartWrite(Table *t) { pthread_mutex_lock(&t->m); if (t->readers>0 || t->writing) pthread_cond_wait(&t->oktowrite,&t->m); t->writing = TRUE; pthread_mutex_unlock(&t->m); } void Table_EndWrite(Table *t) { pthread_mutex_lock(&t->m); t->writing = FALSE; if (pthread_cond_empty(&t->oktoread)) pthread_cond_signal(&t->oktowrite); else pthread_cond_broadcast(&t->oktoread); pthread_mutex_unlock(&t->m); } Semáforos con Monitores int sem_wait(sem_t *sem) { pthread_mutex_lock(&sem->m); if (sem->n>0) sem->n--; else pthread_cond_wait(&sem->anysignal,&sem->m); pthread_mutex_unlock(&sem->m); } int sem_post(sem_t *sem) { pthread_mutex_lock(&sem->m); if (pthread_cond_empty(&sem->anysignal)) sem->n++; else pthread_cond_signal(&sem->anysignal); pthread_mutex_unlock(&sem->m); } Monitores con semáforos typedef struct pthrad_mutex_t; typedef struct{ int n; sem_t cond; } pthread_cond; int pthread_mutex_init(pthread_mutex_t *m, ) { return sem_init(m,0,1); } int pthread_mutex_destroy(pthread_mutex_t *m) { return sem_destroy(m); } int pthread_mutex_lock(pthread_mutex *m) { return sem_wait(m); } int pthread_mutex_unlock(pthread_mutex *m) { return sem_post(m); } int pthread_cond_init(pthread_mutex *c, ) { c-> n = 0; /* número de procesos bloqueados bajo la condición */ return sem_init(&c->cond,0,0); } int pthread_cond_destroy(pthread_cond *c) { return sem_destroy(&c->cond); } int pthread_cond_wait(pthread_cont*c ,pthread_mutex *); { c->n++; sem_post(m); sem_wait(&c->cond); sem_wait(m); } int pthread_cond_signal(pthread_cond *c) { if (c->n>0) { c->n--; sem_post(&c->cond); } return –1; } int pthread_cond_signal(pthread_cond *c) { for(;c->n>0;c->n--) sem_post(&c->cond); return –1; } Paso de Mensajes int socketpair_wait(int *sv, int channel) { char c; return read(sv[1-channel], &c, 1); } int socketpair_post(int *sv, int channel) { char c = ‘p’; return write(sv[ch],&c,1); } int writen(int sd, void *buf, size_t len) { size_t nleft = len; size_t nwritten; const char *ptr = buf; while (nleft>0) { if ((nwritten=write(sd,ptr,nleft))<=0) return nwritten; nleft -= nwritten; ptr += nwritten; } return len; } int readn(int sd, void *buf, size_t len) { size_t nleft = len; size_t nread; const char *ptr = buf; while (nleft>0) { if ((nread=read(sd,ptr,nleft))<0) return nread; nleft -= nread; ptr += nread; } return len; } Productores-Consumidores (Mensajes) (Productors) socketpair_wait(ctl,0); writen(data[0], &p, sizeof(p) ); socketpair_post(ctrl,0); (Consumidors) socketpair_wait(ctl,1); readn(data[1], &p, sizeof(p)); socketpair_post(ctrl,1); Wrapper de la función poll (Mensajes) int waitsel(int timeout, int n, int fd[]) { int i,n; struct pollfd fds[n]; for (i=0;i<n;i++) { fds[i].fs = fd[i]; fds[i].events = POLLIN; } n = poll(fds,n,timeout); switch(n) { case 0: /* timeout */ return –2; case 1: /* error */ return –1; default: for (i=0;i<n && !(fds[i].revents&POLLIN);i++) return fds[i].fd; } } Lectores/Escritores (Mensajes) (Lectores) m->id = reader_id; m->class = READER; writen(data[0], &m, siezof(m) ); /* peticiones por cero */ readn(data[1], &ack, sizeof(ack)); /* esperando ACK */ /* leer tabla (...) */ writen(data[1], &m, siezof(m) ); /* liberamos la tabla */ (Lectores) m->id = writer_id; m->class = WRITER; writen(data[0], &m, siezof(m) ); /* peticiones por cero */ readn(data[1], &ack, sizeof(ack)); /* esperando ACK */ /* escribir en tabla (...) */ writen(data[1], &m, siezof(m) ); /* liberamos la tabla */