Threads Aluna: Gabriela Ross Exercício 1 thread-create.c #include #include #include #include <pthread.h> <stdio.h> <stdlib.h> <unistd.h> #define NUM_THREADS 16 void *threadBody (void *id) //declara o corpo da thread { long tid = (long) id ; //variavel para id da thread printf ("t%02ld: Olá!\n", tid) ; //exibe o id da thread sleep (3) ; //para o programa por 3 segundos printf ("t%02ld: Tchau!\n", tid) ; //exibe o id da thread pthread_exit (NULL); //encerra a thread e retorna nulo (caso n tenha erro) } int main (int argc, char *argv[]) { pthread_t thread [NUM_THREADS] ; //variavel para fazer op. com threads long i, status ; //cria variaveis for (i=0; i<NUM_THREADS; i++) //loop para criar 16 threads { printf ("Main: criando thread %02ld\n", i) ; status = pthread_create (&thread[i], NULL, threadBody, (void *) i) ; if (status) //tratativa de erro na criacao de threads { perror ("pthread_create") ; exit (1) ; } } pthread_exit (NULL) ; //encerra a thread } Print do Terminal Funcionamento do programa O funcionamento desse programa é muito parecido com o anterior, a diferença é que o método thread-join está no escopo também. Sua função é bloquear o thread de chamada até que o thread representado por esta instância seja encerrado. • A ordem de criação, ativação e encerramento das threads é a mesma? Por que? Não. A criação ocorre na ordem crescente, seguindo a ordem do “for”, porém a ativação e o encerramento não. Isso ocorre, pois, a execução das threads depende do escalonamento realizada pelo sistema operacional, que executa uma parcela de código de cada uma das threads em uma dada janela de tempo, incluindo a thread principal, que consiste no corpo função main. Diagrama de tempo Exercício 2 thread-join.c #include #include #include #include <pthread.h> <stdio.h> <stdlib.h> <unistd.h> #define NUM_THREADS 16 void *threadBody(void *id) //declara o corpo da thread { long tid = (long) id ; //variavel para id da thread printf ("t%02ld: Olá!\n", tid) ; //exibe o id da thread sleep (3) ; //para o programa por 3 segundos printf ("t%02ld: Tchau!\n", tid) ; //exibe o id da thread pthread_exit (NULL) ; //encerra a thread e retorna nulo(caso n tenha erro) } int main (int argc, char *argv[]) { pthread_t thread [NUM_THREADS] ; //variavel para fazer op. com threads pthread_attr_t attr ; //variavel para inicializacao dos atributos/objetos long i, status ; //cria variaveis pthread_attr_init (&attr) ; //inicializa os atributos/objetos pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); //define se a thread aguarda a execucao de outra thread relacionada ou nao for(i=0; i<NUM_THREADS; i++) //criacao de threads { printf ("Main: criando thread %02ld\n", i) ; status = pthread_create (&thread[i], &attr, threadBody, (void *) i) ; if (status) //tratativa de erro na criacao de threads { perror ("pthread_create") ; exit (1) ; } } for (i=0; i<NUM_THREADS; i++) { printf ("Main: aguardando thread %02ld\n", i); status = pthread_join (thread[i], NULL) ; //relaciona uma thread com ou tra para que aguarde o termino de sua execucao if (status) //tratativa de erro na criacao de threads { perror ("pthread_join") ; exit (1) ; } } pthread_attr_destroy (&attr) ; //destroy o atributo/objeto da thread pthread_exit (NULL) ; } Print do Terminal Funcionamento do programa A função main contém um vetor de 16 posições de pthreads, para guardar as structs das threads, que são passadas por referência para o método pthread_create, que é encarregado de criar uma thread e inicializar uma thread. O código que será executado pela thread está definido pelo método threadBody e é o corpo da função passado por referência para a função pthread_create. A biblioteca pthread cria e inicia a thread no laço for, e assim 16 threads são criadas. O tempo de processamento será escalonado para cada thread de acordo com decisões do kernel. • Objetivo do parâmetro attr e da chamada pthread_join A função pthread_join vincula uma thread a outra para aguardar seu término e retornar imediatamente quando essa finaliza utilizando o parâmetro attr como atributo. Diagrama de tempo Exercício 3 thread-print.c #include #include #include #include <pthread.h> <stdio.h> <stdlib.h> <unistd.h> #define NUM_THREADS 16 int x = 0 ; //cria variavel x e inicializa com zero void *threadBody (void *id) //declara o corpo da thread { long tid = (long) id ; //variavel para id da thread x++ ; //incrementa x printf ("t%02ld: Olá! (x=%02d)\n", tid, x) ; //exibe o id da thread e o valor de x sleep (3) ; x++ ; //incrementa x printf ("t%02ld: Tchau! (x=%02d)\n", tid, x) ; //exibe o id da thread e o valor de x pthread_exit (NULL) ; //encerra a thread e retorna nulo(caso n haja erro) } int main (int argc, char *argv[]) { pthread_t thread [NUM_THREADS] ; //variavel para fazer op. com threads long i, status ; //cria variaveis for (i=0; i<NUM_THREADS; i++) //loop para criar threads { printf ("Main: criando thread %02ld\n", i) ; status = pthread_create (&thread[i], NULL, threadBody, (void *) i) ; if (status) { perror ("pthread_create") ; exit (1) ; } } pthread_exit (NULL) ; } Print do Terminal Funcionamento do programa O funcionamento do código é basicamente igual ao código do primeiro exercício, porém no corpo da função executada pelas threads a da variável global inteira x é incrementada em dois momentos: antes e depois de uma chamada da função sleep, que faz a thread dormir por três segundos. Analisando os valores da variável conforme as threads são chamadas, é possível perceber que não há garantia da ordem de execução e encerramento devido à imprevisibilidade das decisões do kernel, ao passo que a ordem criação das threads é previsível, devido ao fato que elas são criadas em ordem crescente via chamadas pthread_create no código. Compare a evolução da variável x neste programa com aquela que ocorreria em um programa equivalente usando a chamada de sistema fork. Compare a evolução da variável x neste programa com aquela que ocorreria em um programa equivalente usando a chamada de sistema fork. Thread independe do processo que está ocorrendo, ele sempre incrementa 1 sequencialmente. O fork não consegue fazer essa sequência de soma, ele ficaria trocando valores, pois ele é dependente do processo. Diagrama de tempo