Baixe o app para aproveitar ainda mais
Prévia do material em texto
Posix Threads ● Pthreads = API de threads disponível em diversas arquiteturas e sistemas operacionais ● Usar: #include “pthread.h” ● Compilar: gcc –lpthread pthread.c • Gerenciamento de Threads ● Criação: pthread_create ● Término: ● Return ● pthread_exit ● Sincronização (pai/filho): pthread_join Criação de Threads ● pthread_create(pthread_t * thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg); - thread: parâmetro de saída que conterá o id da nova thread - attr: parâmetro de entrada que especifica os atributos da thread a ser criada (NULL = default) - start_routine: função usada pela threda deve ter o protótipo como: void * foo(void*) - arg: parâmetro a ser passado para a rotina da da thread Se a rotina da thread requerer mais de um parâmetro, eles devem ser empacotados em uma estrutura cujo ponteiro deve ser passado Sincronizando Pai/Filho ● Pthread_create → main thread continua ● pthread_join(pthread_t tid, void **status) - tid = id da thread que se quer esperar - status = estado de retorno da referida thread gerado no pthread_exit Terminando uma Thread ● Retorno normal ● pthread_exit(void *status) - status = estado de retorno #include <stdio.h> #include <stdlib.h> #include <pthread.h> void *print_message_function( void *ptr ); main() { pthread_t thread1, thread2; char *message1 = "Thread 1“, *message2 = "Thread 2"; int iret1, iret2; iret1 = pthread_create( &thread1, NULL, print_msg_function, (void*) message1); iret2 = pthread_create( &thread2, NULL, print_msg_function, (void*) message2); pthread_join( thread1, NULL); pthread_join( thread2, NULL); printf("Thread 1 returns: %d\n",iret1); printf("Thread 2 returns: %d\n",iret2); exit(0); } void *print_msg_function( void *ptr ) { char *message; message = (char *) ptr; printf("%s \n", message); } Passando Múltiplos Parâmetros #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 4 void *BusyWork(void *t) { int i; long tid; double result=0.0; tid = (long)t; printf("Thread %ld starting...\n",tid); for(i = 0; i < 1000000; i++) { result = result + sin(i) * tan(i); } printf("Thread %ld done. Result = %e\n", tid, result); pthread_exit((void*) t); } int main (int argc, char *argv[]) { pthread_t thread[NUM_THREADS]; pthread_attr_t attr; int rc; long t; void *status; /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for(t = 0; t < NUM_THREADS; t++) { printf("Main: creating thread %ld\n", t); rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } /* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr); for(t = 0; t < NUM_THREADS; t++) { rc = pthread_join(thread[t], &status); if (rc) {printf(« ERROR: pthread_join() is %d\n", rc); exit(-1);} printf(« Join with thread %ld with status %ld\n",t,(long)status); } /* All the threads have terminated, now we are done */ printf("Main: program completed. Exiting.\n"); pthread_exit(NULL); } Sincronização ● Exclusão mútua → mutex (mutual exclusion) variables ● Apenas 1 thread pode executar o código protegido por variáveis mutex ● Declaração estática: pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; ● Construção dinâmica: pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr) Sincronização ● Seção crítica: ● pthread_mutex_lock(pthread_mutex_t *mutex) ● pthread_mutex_unlock(pthread_mutex_t *mutex) pthread_mutex_t mutexsum; pthread_mutex_lock(&mutexsum); total_sum += thread_sum; pthread_mutex_unlock(&mutexsum); Sincronização ● Variáveis de condição → permite a sincronização de acordo com condições dentro do programa ● Usadas em conjunto com lock/unlock ● Declaração estática: pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER; ● Construção dinâmica: pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr) Sincronização ● Wait e Signal ● pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) → processo bloqueia ate que a variavel cond seja sinalizada com um signal. Esta rotina deve ser chamada dentro de uma seção crítica (a seção crítica é liberada quando o processo bloqueia na variável de condição). ● pthread_cond_signal(pthread_cond_t *cond) → processo sinaliza para um processo bloqueado na variável de condição #include <sys/time.h> #include <stdio.h> #include <pthread.h> #include <errno.h> #define SIZE 10 pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t espaco_buffer = PTHREAD_COND_INITIALIZER; pthread_cond_t dado_buffer = PTHREAD_COND_INITIALIZER; int b[SIZE]; int size = 0; int ind_c,ind_p=0; main() { pthread_t thread_produtor; pthread_t thread_consumidor; void *producer(); void *consumer(); pthread_create(&thread_consumidor,NULL,consumer,NULL); pthread_create(&thread_produtor,NULL,producer,NULL); pthread_join(thread_consumidor,NULL); } void add_buffer(int i){ b[ind_p] = i; ind_p = (ind_p+1) % SIZE; size++; } int get_buffer(){ int v; v = b[ind_c]; ind_c= (ind_c+1) % SIZE; size--; return v ; } void *producer() { int i = 0; while (1) { pthread_mutex_lock(&buffer_mutex); if (size == SIZE) { pthread_cond_wait(&espaco_buffer,&buffer_mutex); } add_buffer(i); pthread_cond_signal(&dado_buffer); pthread_mutex_unlock(&buffer_mutex); i = i + 1; } pthread_exit(NULL); } void *consumer() { int v; while (1) { pthread_mutex_lock(&buffer_mutex); if (size == 0) { pthread_cond_wait(&dado_buffer,&buffer_mutex); } v = get_buffer(); pthread_cond_signal(&espaco_buffer); pthread_mutex_unlock(&buffer_mutex); } pthread_exit(NULL); } } Slide 1 Slide 2 Slide 3 Slide 4 Slide 5 Slide 6 Slide 7 Slide 8 Slide 9 Slide 10 Slide 11 Slide 12 Slide 13
Compartilhar