Biblioteca Pthread

6
1. Programação em Pthreads  1.1. Introdução A biblioteca de pthreads cumpre os padrões POSIX e nos permite trabalhar com diferentes "traços de execução" (threads) ao mesmo tempo. A diferença entre uma thread e um processo é que os processos não compartilham memória entre si a não ser que seja declarado explicitamente usando algum dos mecanismos de IPC (InterProcess Communication) de Unix, já as threads compartilham totalmente a memória entre elas. Além do mais, para criar threads sao usadas as funções da biblioteca "pthread" ou de qualquer outra que suporte "threads" e para criar processos usaremos a chamada de sistema fork(), que é encontrada em todos os sistemas unix. Como pthreads é uma biblioteca POSIX é possível portar os programas feitos com ela para qualquer sistema operacional POSIX que suporte threads. Exemplos disso são IRIX, BSD, Digital Unix OSF/1, etc. 1.2. Como compilar um programa com pthreads: Para criar programas que façam uso de biblioteca pthread precisamos, em primeiro lugar, da biblioteca em si. Esta vem na maioria de distribuições do linux, e seguramente é instalada juntamente com os outros pacotes para o desenvolvimento de aplicações. Uma vez que tenhamos a biblioteca instalada, deveremos compilar o programa e "linkalo" à biblioteca dependendo do compilador que estamos usando. A forma mais usual de fazer isto é, se estamos usando um compilador GNU gcc, com o seguinte comando: cc programa_com_pthreads.c -o programa_com_pthreads -pthread 1.3. Criação e manipulação de threads Para criar uma thread usaremos a função pthread_create da biblioteca e da estrutura de dados pthread_t que identifica cada thread diferenciando-a das demais e que contem todos os seus dados. O protótipo da função é o seguinte: int pthread_create(pth read_t * thread, pthread_attr_t *attr, void * (*start_routine)(void *), void *arg) * thread: é uma variável do tipo pthread_t que conterá os dados da thread e que nos servirá para identificar a thread quando nos interessar fazer chamadas a biblioteca para realizar alguma ação sobre ela. * attr: é um parâmetro do tipo pthread_attr_t que se deve inicializar previamente com os atributos que queremos que a thread tenha. Entre os atributos estão a prioridade, o algoritmo da thread, etc. Se passarmos como parâmetro NULL, a biblioteca atribuirá a thread atributos por default.

Transcript of Biblioteca Pthread

Page 1: Biblioteca Pthread

7/23/2019 Biblioteca Pthread

http://slidepdf.com/reader/full/biblioteca-pthread 1/6

1. Programação em Pthreads 

1.1. Introdução

A biblioteca de pthreads cumpre os padrões POSIX e nos permite trabalhar comdiferentes "traços de execução" (threads) ao mesmo tempo.A diferença entre uma thread e um processo é que os processos não compartilhammemória entre si a não ser que seja declarado explicitamente usando algum dosmecanismos de IPC (InterProcess Communication) de Unix, já as threads compartilhamtotalmente a memória entre elas. Além do mais, para criar threads sao usadas as funçõesda biblioteca "pthread" ou de qualquer outra que suporte "threads" e para criar processosusaremos a chamada de sistema fork(), que é encontrada em todos os sistemas unix.Como pthreads é uma biblioteca POSIX é possível portar os programas feitos com elapara qualquer sistema operacional POSIX que suporte threads. Exemplos disso são

IRIX, BSD, Digital Unix OSF/1, etc.

1.2. Como compilar um programa com pthreads:

Para criar programas que façam uso de biblioteca pthread precisamos, em primeirolugar, da biblioteca em si. Esta vem na maioria de distribuições do linux, e seguramenteé instalada juntamente com os outros pacotes para o desenvolvimento de aplicações.Uma vez que tenhamos a biblioteca instalada, deveremos compilar o programa e"linkalo" à biblioteca dependendo do compilador que estamos usando.

A forma mais usual de fazer isto é, se estamos usando um compilador GNU gcc, com oseguinte comando:cc programa_com_pthreads.c -o programa_com_pthreads -pthread

1.3. Criação e manipulação de threads

Para criar uma thread usaremos a função pthread_create da biblioteca e da estrutura dedados pthread_t que identifica cada thread diferenciando-a das demais e que contemtodos os seus dados.O protótipo da função é o seguinte:

int pthread_create(pthread_t * thread, pthread_attr_t *attr, void * (*start_routine)(void*), void *arg)

* thread: é uma variável do tipo pthread_t que conterá os dados da thread e que nosservirá para identificar a thread quando nos interessar fazer chamadas a biblioteca pararealizar alguma ação sobre ela.* attr: é um parâmetro do tipo pthread_attr_t que se deve inicializar previamente com osatributos que queremos que a thread tenha. Entre os atributos estão a prioridade, o

algoritmo da thread, etc. Se passarmos como parâmetro NULL, a biblioteca atribuirá athread atributos por default.

Page 2: Biblioteca Pthread

7/23/2019 Biblioteca Pthread

http://slidepdf.com/reader/full/biblioteca-pthread 2/6

* start_routine: aqui colocamos o endereço da função que queremos que a threadexecute. A função deve devolver um ponteiro genérico (void *) como resultado, e deveter como único parâmetro um outro ponteiro genérico.A vantagem dos ponteiros serem genéricos é que podemos devolver qualquer coisa quese queira através dos castings dos tipos.Se necessitarmos passar ou devolver mais de um parâmetro de uma vez, se pode criaruma estrutura e incluir ali tudo o que é necessário. Logo passaremos ou devolveremos ocaminho desta estrutura como um único parâmetro. (ver código do exemplo)* arg: é um ponteiro ao parâmetro que passaremos para a função. Pode ser NULL se nãoquisermos passar nada para a função.* Em caso de sucesso, a função retorna 0 ou um valor de diferente de 0 caso tenhahavido algum erro.

Uma vez que tenhamos chamado esta função, já teremos a(s) nossa(s) thread(s)funcionando, mas agora temos duas opções: esperar que as threads terminem, caso nosinteresse recuperar algum resultado, ou simplesmente deixamos a biblioteca de pthreadsdecidir que quando termine a execução da função da thread elimine todas os dados desuas tabelas internas.Para isso, dispomos de duas funções adicionais da biblioteca: pthread_join epthread_detach.

int pthread_join(pthread_t th, void **thread_return)

* Esta função suspende a thread que a chamou até que termine a execução da threadindicada por th. Além do mais, uma vez que esta última termina, o resultado é colocadoem thread_return devolvendo para a thread que estava executando.* th: É o identificador da thread que queremos esperar, e é o mesmo que indicamosquando criamos com o pthread_create.* thread_return: É um ponteiro de um ponteiro que aponta para o resultado devolvidopela thread que estamos esperando quando esta termina a sua execução. Se esteparâmetro for NULL, estamos dizendo que o resultado não importa.* Devolve 0 em caso de sucesso, e valor diferente de 0 em caso de algum erro.

int pthread_detach(pthread_t th)

* Esta função indica para a biblioteca que não queremos que o resultado da threadindicada por th seja guardado. Por padrão, o resultado da execução de todas as threadssão guardados até que façamos um pthread_join para recuperar o resultado.É por isso que se não nos interessa o resultado das threads temos que indicar isso comesta função. Assim uma vez que a thread tenha terminado, a biblioteca eliminará todosos dados da thread de suas tabelas internas e teremos mais espaço para criar outras

threads.

Page 3: Biblioteca Pthread

7/23/2019 Biblioteca Pthread

http://slidepdf.com/reader/full/biblioteca-pthread 3/6

* th: É o indentificador da thread.* Devolve 0 em caso de sucesso, e valor diferente de 0 em caso de algum erro.Até agora estivemos falando sobre devolver valores quando a thread finaliza, mas nãodizemos como se faz. Pois bem, para isso temos a função pthread_exit.

void pthread_exit(void *retval)

* Esta função termina a execução da thread que a chama.* retval: É um ponteiro genérico para os dados que queremos retornar como resultado.Estes dados serão recolhidos mais tarde quando alguém fizer um pthread_join com onosso identificador de thread.* Não devolve nenhum valor.

Com tudo que vimos até agora, já estamos preparados para fazer nosso primeiro

problema com pthreads. O programa de exemplo criará MAX_THREADS threads queexecutarão a função function_thr. Esta função imprimirá uma mensagem na tela do tipo"sou a thread número x", onde x será um número diferente para cada thread.Para passar estes parâmetros para a função usaremos um struct de C, onde colocaremoso vetor que deverá conter cada thread juntamente com seu identificador. (Esta cadeiapoderia ser colocada diretamente dentro da função, mas desta forma aproveitaremospara ver como fazer para passar mais de um parâmetro para a thread) Uma vez quetermine sua execução, a thread devolverá com resultado seu identificador (codificadoem um inteiro), que será impresso na tela pela "thread-pai" que esperará que todas as

outras threads terminem.

exemplo: /*** Arquivo ex1.c ***/ #include#include#include#include

#define MAX_THREADS 10

 //tabela com os identificadores das threadspthread_t tabela_thr[MAX_THREADS];

 //tipo de dados e tabela com os parâmetrostypedef struc {int id;char *cadeia;} thr_param_t;

thr_param_t param[MAX_THREADS]; //Tivemos que criar uma tabela para os parâmetros pois os passamos por referência.

Page 4: Biblioteca Pthread

7/23/2019 Biblioteca Pthread

http://slidepdf.com/reader/full/biblioteca-pthread 4/6

 //Assim, se só tivermos uma variável para os parâmetros, ao modificá-la estaremos //modificando todas as que havíamos passado anteriomente, porque as threads não //armazenam os valores e sim os endereços

void *função_thr(thr_param_t *p){

 //Esta é a função que as threads executam //Como se pode ver não há maiores segredosprintf("%s %d\n", p->cadeia, p->id);

 //Uma vez que terminamos, devolvemos o valorpthread_exit(&(p->id));}

int main (void){int i, *res;

 //criamos as theadsprintf("Criando as threads...\n");for(i=0; iparam[i].cadeia = strdup("Olá, sou a thread");

param[i].id = i;

pthread_create(&tabela_thr[i], NULL, (void*)&função_thr, (void*) & param[i]);} //esperamos que as threads terminemprintf("Threads criadas. Esperando que terminem...\n");for(i=0; ipthread_join(tabela_thr[i], (void*)&res);

printf("A thread %d retornou o valor %d\n", i, *res);}

 //imprimimos uma mensagem e saimos do programaprintf("Todas as threads terminadas!\n");

return(0);}

fim do exemplo!

Para compilar (com o gcc do Linux): gcc ex1.c -o ex1 -pthread

O exemplo é em si bastante simples, mas é o esquema básico ao qual seguem todas as

aplicações que criam uma thread para realizar um cálculo e esperam por seu resultadode retorno:

Page 5: Biblioteca Pthread

7/23/2019 Biblioteca Pthread

http://slidepdf.com/reader/full/biblioteca-pthread 5/6

1. Criar a(s) thread(s)2. Esperar que termine(m)3. Recolher e processar os resultadosIsto é um exemplo do que chamamos de paralelismo estruturado.

Um exemplo de um programa que use a função pthread_detach poderia ser o de umservidor (de qualquer coisa: de correio, de http, de ftp, etc) que crie um traço deexecução para cada solicitação que receba. Como o que nos interessa é o resultado daexecução, uma vez que criármos uma thread chamaremos a função pthread_detach.Isto é o que se conhece por paralelismo não estruturado. Ou seja, nossos programas nãoseguem uma estrutura concreta, e vão se ramificando de acordo com as nossasnecessidades.

1.4. Outras funções úteis da biblioteca pthread: 

Até agora vimos apenas as funções mais básicas para se tratar com pthreads.Começaremos então a analisar outras funções úteis:

1) pthread_t pthread_self(void)

- Esta função retorna para a thread que realiza a chamada sua informação, em forma devariável do tipo pthread_t.

É útil nos casos em que a própria thread que se está executando quer trocar seusatributos, ou seja, fazer em si mesma um pthread_detach, etc.- Devolve o identificador da thread.

Exemplo:#include...void *funcion_threads(void *param){pthread_t eu_mesmo;...

 /*nós mesmo nos fazemos o detach*/ eu_mesmo = pthread_self();pthread_detacc(eu_mesmo);...}int main (void){...

}

Page 6: Biblioteca Pthread

7/23/2019 Biblioteca Pthread

http://slidepdf.com/reader/full/biblioteca-pthread 6/6

2) int pthread_kill(pthread_t thread, int signo)

- Envia um sinal específico para a a thread especificada. Um sinal útil pode ser oSIGKILL, ou algum dos definidos pelo usuário, SIGUSR1 e SIGUSR2.Mesmo que possa parecer útil à primeira vista, a única utilidade que tem é matar umathread a partir do processo pai. Se quiseres usar um com fins de sincronização, háformas melhores de se fazer, tratando-se de threads: mediante semáforos e variáveis decondição (veremos em seguida).- thread: identifica a thread para a qual queremos enviar o sinal.- signo: número do sinal que queremos enviar para a thread. Podemos usar as constantesdefinidas em usr/include/signa.h.- Retorna 0 se não ocorrer erro, e diferente de 0 se houver erro.