threads bauke a. dijkstra lucas alves allan f. furukita

43
Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Upload: ana-luiza-medina-barroso

Post on 07-Apr-2016

217 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Threads

Bauke A. DijkstraLucas Alves

Allan F. Furukita

Page 2: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Threads

• Threads, como processos são mecanismos para permitir um programa fazer mais de uma coisa ao mesmo tempo

• Como processo as threads aparentam correr simultaneamente

• O Linux kernel interrompe cada thread de tempo em tempo para dar chance de outros executar

• Conceitualmente uma threads está dentro do processo

Page 3: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Quando é executado um programa, é criado um processo e dentro desse é criado uma única thread que pode criar outras threads

• Ao criar uma nova thread nada é copiado, pois eles já compartilham a mesma memória, espaço, descrição, e outros recursos do sistema

• Se uma thread mudar o valor de uma variável a thread subsequente ira ver o valor alterado

• GNU/Linux implementa o POSIX thread API, todas funções e tipo de data são declarados no cabeçalho do arquivo

• Como a pthread não esta incluido na biblioteca padrao de C, para compilar você deve adicionar –lpthread pois ela esta na libpthread

Page 4: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Criação de threads• Cada thread possui sua ID• Na criação em a thread executa a thread function, quando

retorna algum valor é porque ela existe• Em C e C++ usam o tipo pthread_t• A função pthread_create possui 4 parametros, (id,

atributo, ponteiro da função, argumento)• A chamada de pthread_create retorna imediatamente e a

thread original continua a executar as instruções seguindo a chamada, enquanto a nova thread começa a função thread

• Seu programa não pode depender da ordem de execuções das threads

Page 5: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita
Page 6: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Como passar dados para Threads?

• É utilizado o argumento para a passagem de dados

• Normalmente é definido uma estrutura para cada função thread que possui os parametros que é esperado

Page 7: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Juntando Threads

• É feita a partir da função pthread_join, que possui dois parâmetros. O id da thread que tem que esperar e um ponteiro que irá receber o retorno da thread quando terminar

• Caso não seja necessário o valor de retorno utiliza o NULL

• Caso seja diferente de NULL o valor de retorno será armazenado no local apontado pelo argumento

Page 8: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Mais sobre Thread’s Ids

• A função pthread_self retorna o a ID da thread que foi chamada

• A função pthread_equal serve para comparar os ID das threads

Page 9: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Atributos de Threads

• Providencia um mecanismo para melhorar o comportamento da thread

• Você pode criar e customizar atributos de objeto da thread para especificar outros valores para os atributos

• Para especificar uma thread customizada você deve, criar pthread_attr_t, chamar pthread_attr_init, modificar o atributos de objeto da thread para conter o que é desejado, passar um ponteiro para o objeto quando chamar pthread_create, chamar pthread_attr_destroy

Page 10: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Um unico atributos de objeto da thread pode ser usado para começar varias threads

• Não é necessário deixar o atributos de objetos da thread ao redor depois que as threads foi criada

• Uma Thread pode ser declarada como joinable thread ou como detached thread

• Joinable thread não é limpada automaticamente quando terminada já a detached thread limpa automaticamente e por isso essa não pode ser sincronizada com outra thread

• Para escolher o estade detach no atributo de objeto da thread utiliza pthread_attr_setdetachstate sendo o primeiro parametro um ponteiro para o atributo de objeto da thread, e o segundo o estado desejado de detach

Page 11: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Cancelamento da Thread

• A função utilizada é a pthread_cancel, passando a ID da thread

• Ela pode ser juntada depois de cancelada• Para liberar seus recursos ela deve ser juntada• Temos três estados em relação ao cancelamento

das threads• Cancelamento assíncrono• Cancelamento síncrono (padrão)• Incancelável

Page 12: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Threads Síncrona e Assíncrona

• Uma thread cancelável assíncrona pode ser cancelada em qualquer ponto da execução, já a síncrona pode ser cancelada em pontos específicos da execução

• Para deixar uma thread cancelável assíncrona utilize pthread_setcanceltype, que afeta a thread que chamou a função.

pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

• Para criar pontos de cancelamento utiliza-se o pthread_testcancel

Page 13: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Seções Críticas Incancelável

• A thread pode desabilitar o cancelamento usando a função pthread_setcancelstate

• pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);

• Usando a função acima habilita a implementação de seções críticas

• Seções críticas é uma seqüência de códigos que não pode ser cancelado enquanto não estiver pronto

Page 14: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Quando usar cancelamento da Thread

• No geral não é aconselhável utilizar cancelamento de uma thread para finalizar a execução de uma thread, exceto em circunstancias incomuns.

• A melhor estratégia é indicar a thread que deve sair e esperar ela terminar de maneira normal.

Page 15: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Dados específicos da Thread

• As threads pertencentes a um processo compartilham os dados do processo.

• Esse compartilhamento de dados fornece um dos benefícios da programação multithreads.

• Em certas circunstancias, cada thread poderia precisar de sua própria copa de certos dados.

• Você pode criar quantos dados específicos da thread que quiser, sendo do tipo void*

Page 16: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Cada item é referenciado por uma chave• Para criar uma nova chave é usado a função

pthread_key_create• O primeiro argumento é um ponteiro para a

variavel pthread_key_t• O segundo argumento para pthread_key_t é

uma função de limpeza, pode-se passar null caso não precise de uma função de limpeza.

Page 17: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Depois da chave ser criada, cada thread pode definir seu valor de thread-específico correspondendo a chave chamando pthread_setspecific.

• O primeiro argumento é a chave• O segundo argumento é o valor do void*

thread-específico para armazenar• Para recuperar os dados do thread-específico,

se chama pthread_getspecific, passando a chave como seu argumento.

Page 18: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Cleanup Handlers

• São funções chamadas quando a thread é terminada ou cancelada.

• Ela é útil por ser capaz de especificar funções de limpeza sem criar um novo dado de thread específico que esta duplicado pra cada thread.

• O GNU/LINUX te da esse recurso com esse proposito.

• O handler toma um parâmetro void* e o valor do argumento é dado quando o handler é registrado.

Page 19: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Um Cleanup Handler é uma medida temporária, usada para desalocar um recurso somente se a thread é fechada ou cancelada.

• Caso a thread não sair ou for cancelada, o cleanup handler deve ser removido e o recurso desalocado explicitamente.

• Para registrar um cleanup handler, deve-se chamar pthread_cleanup_push, passando um ponteiro para a função de limpeza e o valor do argumento void*

Page 20: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• A chamada para pthread_cleanup_push deve ser equilibrada por uma chamada correspondente para pthread_cleanup_pop, que cancela o registro de limpeza handler.

• Como uma conveniência pthread_cleanup_pop leva um argumento int flag

• Se a flag é diferente de zero, a ação de limpeza é realizada, uma vez que não é registrada.

Page 21: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Thread Cleanup em C++

• Quando os objetos saem do escopo, C++ garante que os destructors sejam chamados para essas variáveis automáticas, fornecendo um código de limpeza que é chamado não importando como o bloco foi encerrado.

• Se uma thread chama pthread_exit, a linguagem C++ não garante que os destructors sejam chamados para todas variáveis automáticas

• A melhor forma para recuperar essa funcionalidade é usar pthread_exit no nível superior da função thread jogando uma exceção especial

Page 22: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Sincronização e Sessões Críticas

• Programar com threads é muito complicado, por causa da sua concorrência. É impossível saber quando o sistema irá agendar e executar uma thread.

• Para fazer um “debbuging” é complicado, pois você pode executar o programa e funcionar, mas na próxima ele pode falhar.

Page 23: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Condições de Corrida

• A causa definitiva da maioria dos problemas que envolvem threads é que estes estão acessando os mesmos dados. Se uma thread usa parcialmente uma estrutura de dados enquanto outra acessa a mesma estrutura, problemas são suscetíveis de acontecer.

• Quando uma thread fica agendada mais ou menos frequentemente que outra pode ocorrer um erro conhecido como condição de corrida.

Page 24: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita
Page 25: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

A depuração de programas que contenham condições de corrida não é nada simples. Os

resultados da maioria dos testes não apresentam problemas, mas em algum

momento algo estranho pode acontecer.

Page 26: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Sessões Críticas

O problema de evitar condições de disputa pode ser formulado de um modo abstrato. Durante

uma parte do tempo, um processo está ocupando fazendo coisas que não levam a

condições de disputa. Porém, algumas vezes ele precisa ter acesso à memória ou outra coisas que pode ocasionar disputas. Na parte do programa

onde há acesso à memória compartilhada é chama ou sessão critica ou região crítica

Page 27: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Porém, mesmo que evite-se as condições de disputa, é necessário satisfazer 4 condições para chegar a uma boa solução:

1. 2 Processos nunca podem estar simultaneamente em suas regiões críticas.

2. Nada pode ser afirmado sobre a velocidade ou sobre o número de CPUs.

3. Nenhum processo executando fora de sua região crítica pode bloquear outros processos

4. Nenhum processo deve esperar eternamente para entrar em sua região crítica.

Page 28: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Exclusão mútua

• É um modo de assegurar que outros processos sejam impedidos de usar uma variável ou um arquivo compartilhado que já estiver em uso por um processo.

Page 29: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita
Page 30: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Semáforos

• É uma variável especial que tem como função o controle de acesso a recursos compartilhados. O valor de um semáforo indica quantas threads podem ter acesso a um recurso compartilhado.

• Edsger Dijkstra, criador do semáforo propôs a existência de duas operações, down e up (ou sleep e wakeup, respectivamente).

Page 31: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Down: Verifica se o valor do semáforo é maior que zero. Se sim, decrementará o valor e prosseguirá. Se o valor for zero, o processo será posto para dormir, sem terminar o down, pelo menos por enquanto.

• Up: Incrementa o valor de um dado semáforo. Se um ou mais processos estivessem dormindo naquele semáforo, um deles seria escolhido pelo sistema e seria dada a permissão para terminar seu down.

Page 32: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Mutexes

Um mutex (abreviação de mutual exclusion, exclusão mútua) é uma versão simplificada de

semáforo e só é adequado para gerenciar a exclusão mútua de algum recurso ou parte de

código compartilhada.

Page 33: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Mutexes são fáceis de implementar e eficientes, o que os torna especialmente úteis em pacotes de threads implementados totalmente no espaço do usuário.

• Um mutex é uma variável que tem dois estados (desimpedido ou impedido) e consequentemente, somente 1 bit é necessário para representá-lo.

Page 34: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Quando um thread precisa ter acesso a uma região crítica, ele chama mutex_lock. Se o

mutex estive desimpedido, a chamada prosseguirá.

Por outro lado, se o mutex já estiver impedido, o thread que chamou mutex_lock, permanecerá bloqueado até que o thread na região crítica

termine e chame mutex_unlock.Se vários threads estiverem bloqueados sobre o

mutex, um deles será escolhido e liberado para adquirir a trava.

Page 35: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita
Page 36: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Barreiras

Algumas aplicações são divididas em fases e têm como regra que nenhum processo pode

avançar para a próxima fase até que todos os processos estejam prontos a fazê-lo. Isso pode

ser conseguido por meio da colocação de uma barreira no final de cada fase. Quando alcança a barreira, um processo permanece

bloqueado até que todos os processos alcancem a barreira.

Page 37: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita
Page 38: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Implementação de thread GNU/Linux

• A implementação de threads POSIX no GNU/Linux é diferente da implementação em outros sistemas UNIX.

• No GNU/Linux threads são implementados como processos.

• Quando se chama pthread_create para criar uma nova thread, o Linux cria um novo processo para executar a thread

Page 39: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Manipulação de sinais

• O comportamento de interação entre sinais e threads variam de um sistema tipo UNIX para outro.

• No GNU/Linux o comportamento é ditado por um fato que as threads são implementadas como processos.

• Uma vez que cada thread é um processo separado, e porque um sinal é emitido para determinado processo, não há ambiguidade sobre qual thread recebe o sinal.

Page 40: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Normalmente sinais são enviados de fora do programa ao processo correspondente ao thread principal.

• Em um programa multithread, é possível para um thread enviar um sinal específico para outro thread, usando a função pthread_kill. Passando o ID da thread como seu primeiro parâmetro e um numero de sinais como seu segundo parâmetro.

Page 41: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Chamada de Sistema clonada

• A chamada de sistema clonada do Linux é uma forma generalizada de fork e pthread_create que permite especificar os recursos compartilhados entre o processo de chamada e o novo processo criado.

• O clone requer que especifique a região da memória para a execução da pilha que o novo processo use.

• Para criar novos processos use fork• Para criar novas threads use pthread_create

Page 42: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

Processos x Threads

• Todos threads em um programa deve rodar o mesmo executável. Um processo filho pode rodar um executável diferente chamando uma função exec.

• Um thread errante pode prejudicar outros threads no mesmo processo porque compartilham o mesmo espaço de memória virtual e outros recursos. Um processo errante não prejudica pois cada processo tem uma cópia do espaço de memória do programa.

Page 43: Threads Bauke A. Dijkstra Lucas Alves Allan F. Furukita

• Threads deve ser usada em sistema paralelo de grão fino, em que o problema pode ser dividido em várias tarefas semelhantes. Processo deve ser usado em sistema paralelo de grão grosso.

• Compartilhamento de dados entre threads é trivial porque threads compartilham a mesma memória. O compartilhamento de dados entre os processos requer o uso de mecanismos de IPC.