threads e sincronizathreads e sincronizaççãoãosimone/scminter/contaulas/11_thsin.pdf · threads...
TRANSCRIPT
Sistemas de Computação
Threads e SincronizaçãoThreads e Sincronização
Sistemas de Computação
Processos concorrentes
• Os processos em execução sob um sistema operacional podem ser:
– independentes (não há interferência entre eles) – cooperativos (há interferência entre eles)
• Processos cooperativos podem compartilhar informações e acelerar execução
• Execução concorrente de processos cooperativos exige mecanismos para comunicação e sincronização
Sistemas de Computação
Processos com 1 ou várias threads
Sistemas de Computação
Benefícios
• Tempo de resposta
• Compartilhamento de recursos
• Economia
• Utilização em arquiteturas multiprocessadas
Sistemas de Computação
Threads do usuário
• Gerenciamento das threads é realizado utilizando-se bibliotecas para threads oferecidas ao usuário
• Exemplos
- POSIX Pthreads
- Mach C-threads
- Solaris threads
Sistemas de Computação
Threads do núcleo
• Suportadas pelo núcleo
• Exemplos
- Windows 95/98/NT/2000
- Solaris
- Linux
Sistemas de Computação
Modelo multithreading- muitas para uma
• Mapeia várias threads do usuário em uma do núcleo
• Utilizada em núcleos que não suportam threads de núcleo
Sistemas de Computação
Modelo multithreading- uma para uma
• Cada thread de usuário é mapeada em uma thread de núcleo
• Exemplos- Windows 95/98/NT/2000- OS/2
Sistemas de Computação
Modelo multithreading-muitas para muitas
• Mapeia várias threads do usuário em um número igual ou menor de threads de núcleo
• Exemplos:– Solaris 2, IRIX, HP-UX
Sistemas de Computação
Chamadas do sistema fork() e exec()
• O comando fork() quando chamado deve gerar 1 processo com todas as threads do processo ou somente uma única thread?
• Caso se queira executar novo programa não precisaria duplicar todas as threads, caso contrário sim
Sistemas de Computação
Cancelamento de threads
• Assíncrono– uma thread pode finalizar imediatamente outra
• Adiado– uma thread checa se ela deve ser cancelada e ela é responsável
pelo seu cancelamento
Sistemas de Computação
Manipulação de sinais
• Um sinal é gerado pela ocorrência de um evento
• O sinal gerado é entregue a um processo, que deve ser tratado por ele
• Síncrono: evento gerado pelo processo– divisão por 0
• Assíncrono: evento externo ao processo– control-C ou expiração de time slice
• Sinal deve ser tratado por tratamento default ou do usuário
Sistemas de Computação
Manipulação de sinais
• Em um ambiente multithreaded quem deve receber o sinal?
– Thread para a qual o sinal se aplica– Todas as threads– Algumas threads– Uma thread específica criada para somente atender sinais
Sistemas de Computação
Repositório de threads
• Número determinado de threads já existe em um repositório
• Ativadas quando requisitadas
• Mais rápido atender pedidos de threads
• Limita número de threads existente
Sistemas de Computação
Dados específicos da thread
• As threads de um determinado processo compartilham todos os dados
• Algumas bibliotecas de threads permitem que threads possuam dados específicos dela
Sistemas de Computação
Pthreads
• Um padrão POSIX (IEEE 1003.1c) API para criação e sincronização de threads
• A API especifica o comportamento da biblioteca de threads, a implementação depende de cada implementador
• Comum em UNIX
Sistemas de Computação
Pthreads
#include<pthread.h>#include<stdio.h>
int sum;void *runner (void *param);main(int argc, char *argv[]){
pthread_t tid;pthread_attr_t attr;/* obtém atributos default */pthread_attr_init(&attr);/* cria a thread */pthread_create(&tid,&attr,runner,argv[1]);
/* espera a thread acabar */pthread_join(tid,NULL);printf(“soma= %d\n”,sum);}
void *runner(void *param){
int upper=atoi(param);int i;sum =0;for (i=1; i<=upper;i++)
sum +=1;pthread_exit(0);
}
Sistemas de Computação
Java Threads
• Threads em Java podem ser criadas:– Estendendo-se a classe Thread– Implementando como uma interface Runnable
• Threads em Java são gerenciadas pela JVM
Sistemas de Computação
Processos ou threads concorrentes
• Acesso concorrente a dados compartilhados pode resultar em inconsistência de dados
• Para manter a consistência dos dados, devem existir mecanismos que assegurem a execução de forma ordenada dos processos cooperativos
Sistemas de Computação
Problema do produtor-consumidor
• O produtor produz informação consumida pelo consumidor
– buffer ilimitado: não impõe limites práticos no tamanho do buffer.– buffer limitado: assume que o buffer possui um tamanho fixo
Sistemas de Computação
Buffer limitado com memória compartilhada
• Dado compartilhado#define BUFFER_SIZE 10typedef struct {
. . .} item;item buffer[BUFFER_SIZE];int in = 0;int out = 0;
• A variável in aponta para a próxima posição livre do buffer e out para a primeira posição cheia do buffer
• in == out, buffer vazio• out == ((in+1)%BUFFER_SIZE), buffer cheio
Sistemas de Computação
Processo produtor
item nextProduced;
while (1) {
/* espera buffer esvaziar */
while (((in + 1) % BUFFER_SIZE) == out);
/* coloca item no buffer */
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
}
Sistemas de Computação
Processo consumidor
item nextConsumed;
while (1) {
/* espera elemento no buffer */
while (in == out);
/* lê elemento do buffer */
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
}
Sistemas de Computação
Solução para ter mais elementos no buffer
• Dado compartilhado
#define BUFFER_SIZE 10typedef struct {
. . .} item;item buffer[BUFFER_SIZE];int in = 0;int out = 0;int counter = 0;
• Na solução anterior, só se pode ter no máximo BUFFER_SIZE -1 elementos no buffer
Sistemas de Computação
Processo produtor
item nextProduced;
while (1) {
/* espera buffer esvaziar */
while (counter == BUFFER_SIZE);
/* coloca elemento no buffer */
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
counter++;
}
Sistemas de Computação
Processo consumidor
item nextConsumed;
while (1) {
/* espera existir elemento */
while (counter == 0);
/* lê elemento */
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
}
Sistemas de Computação
Problemas no acesso concorrente
• A instrução “count++” pode ser implementada em linguagem de máquina como :
register1:= counter;register1:= register1+1;counter:= register1;
• A instrução “count—” pode ser implementada como:
register2:= counter;register2:= register2-1;counter:= register2;
Sistemas de Computação
Problemas no acesso concorrente
• Se o produtor e consumidor tentarem atualizar o buffer concorrentemente, as instruções de linguagem de máquina podem ser executadas de modo intercalado
• O intercalamento depende de como os processos produtor e consumidor são escalonados
Sistemas de Computação
Problemas no acesso concorrente
• Assuma counter com valor inicial 5. Um intercalamento de instruções poderia ser:
produtor: register1 = counter (register1 = 5)produtor: register1 = register1 + 1 (register1 = 6)consumidor: register2 = counter (register2 = 5)consumidor: register2 = register2 – 1 (register2 = 4)produtor: counter = register1 (counter = 6)consumidor: counter = register2 (counter = 4)
• O valor de count pode ser ou 4 ou 6, quando o resultado correto deveria ser 5
Sistemas de Computação
Problemas no acesso concorrente
• As instruçõescounter++;counter--;devem ser executadas atomicamente
• Operação executada de forma atômica significa que uma operação é completada inteiramente atéo fim, sem ser interrompida
Sistemas de Computação
Condição de corrida
• Condição de corrida: Situação em que vários processos acessam e manipulam dados concorrentemente
• Valor final do dado compartilhado depende de qual processo acaba primeiro
• Para prevenir condições de corrida, os processos concorrentes devem ser sincronizados
Sistemas de Computação
Problema da seção crítica
• n processos competindo para utilizar algum dado compartilhado
• Cada processo possui um segmento de código, chamado seção crítica, no qual o dado compartilhado é acessado
• O problema é assegurar que quando um processo está executando instruções de sua seção crítica, nenhum outro processo pode executar instruções que acessem o dado compartilhado, ou seja, uma seção crítica
Sistemas de Computação
Estrutura geral de um processo Pi
do {
entry section
critical section
exit section
remainder section
} while (1);
Sistemas de Computação
Requerimentos para resolver o problema da seção crítica
1. Exclusão mútua: se o processo Pi está executando em sua seção crítica, os outros processos não podem estar executando na seção crítica deles
2. Progresso: Se nenhum processso está executando em sua seção crítica e alguns processos querem entrar na seção crítica deles, então somente os processos que não estão executando na seção remainder podem participar da decisão de quem vai ser o próximo processo a entrar na seção crítica e esta seleção não pode ser adiada indefinidamente
Sistemas de Computação
Requerimentos para resolver o problema da seção crítica
3. Espera limitada: Deve existir um limite no número de vezes que outros processos ganham direito de entrar na seção crítica, depois que um processo faz um pedido de entrada e antes que o pedido tenha sido atendido
Sistemas de Computação
Tentativas para resolver o problema
• Cada processo executa com velocidade diferente de 0
• Nada é assumido sobre a velocidade relativa de execução dos n processos
• Instruções básicas de linguagem de máquina são realizadas de forma atômica
• Soluções serão mostradas para dois processos
Sistemas de Computação
Algoritmo 1
• Variáveis compartilhadas: – int turn;
inicialmente turn = 0– turn == i Pi pode entrar na sua seção crítica
• Processo Pido {
while (turn != i) ;critical sectionturn = j;remainder section
} while (1);• Satisfaz exclusão mútua, mas não garante
progresso
Sistemas de Computação
Algoritmo 2
• Variáveis compartilhadas– boolean flag[2];
inicialmente flag [0] = flag [1] = false.– flag [i] == true indica que Pi está pronto para entrar na sua
seção crítica
• Process Pido {
flag[i] := true;while (flag[j]) ;critical sectionflag [i] = false;remainder section
} while (1);
Sistemas de Computação
Algoritmo 2
• Satisfaz exclusão mútua, mas não satisfaz requerimento de progresso
T0: P0 coloca flag[0]=true
T1: P1 coloca flag[1]=true
P0 e P1 ficarão em loop eterno
Sistemas de Computação
Algoritmo 3
• Combinação das variáveis compartilhadas do algoritmo 1 e 2
• Processo Pi
do {flag [i]:= true;turn = j;while (flag [j] && turn == j) ;
critical sectionflag [i] = false;
remainder section} while (1);
Sistemas de Computação
Algoritmo 3
• Exclusão mútua – Pi só entra na seção crítica se flag[j]==false ou turn == i– Para os dois processos estarem juntos nas suas seções críticas,
flag[0]==flag[1]==true e turn == 0 == 1 (impossível)
• Progresso e espera limitada– Se Pj não está pronto para entrar na seção crítica, então
flag[j]==false e Pi pode entrar– Se Pj está pronto e turn == i, Pi entra– Se Pj está pronto e turn==j, Pj entra e ao sair reseta flag[j] para
false, permitindo que Pi entre– Pi irá entrar na seção crítica (progresso) após no máximo uma
entrada de Pj (espera limitada)
Sistemas de Computação
Sincronização por hardware
• Instruções que testam e modificam o conteúdo de uma palavra atomicamente boolean TestAndSet(boolean &target) {
boolean rv = target;target = true;return rv;
}
Sistemas de Computação
Exclusão mútua com Test-and-Set
• Dado compartilhado– boolean lock = false;
• Processo Pi
do {while (TestAndSet(lock)) ;critical sectionlock = false;remainder section
}while (1)
Sistemas de Computação
Sincronização por hardware
• Troca o valor entre duas variáveis de forma atômica
void Swap(boolean &a, boolean &b) {
boolean temp = a;
a = b;
b = temp;
}
Sistemas de Computação
Exclusão mútua utilizando troca
• Dados compartilhados (inicializado para false): boolean lock;
• Processo Pido {
key = true;while (key == true)
Swap(lock,key);critical sectionlock = false;remainder section
} while (1)
Sistemas de Computação
Semáforos
• O semáforo S é uma variável inteira que só pode ser acessada por duas operações atômicas:
– wait (S): while S 0 do no-op;S--;
– signal (S): S++;
Sistemas de Computação
Seção crítica de n processos
• Dados compartilhados:semaphore mutex; //inicialmente mutex = 1
• Processo Pi:
do {wait(mutex);
critical section
signal(mutex);remainder section
} while (1);
Sistemas de Computação
Implementação de semáforos
• Define uma estrutura para o semáforo
typedef struct {
int value;struct process *L;
} semaphore;
• Assume duas operações simples:– block suspende o processo que a chamou– wakeup(P) reinicia a execução de um processo bloqueado P
Sistemas de Computação
Implementação
• Nova definição das operações para semáforos:– wait(S):
S.value--;
if (S.value < 0) {
add this process to S.L;block;
}
– signal(S): S.value++;
if (S.value <= 0) {
remove a process P from S.L;wakeup(P);
}
Sistemas de Computação
Deadlock
• Dois ou mais processos estão esperando indefinidamente por um evento que só pode ser causado por um dos processos que também estáesperando por um evento
• Suponha que S e Q são semáforos inicializados com o valor 1
P0 P1wait(S); wait(Q);wait(Q); wait(S);
. .
. .signal(S); signal(Q);signal(Q) signal(S);