Sinc_Threads.ppt

Download Report

Transcript Sinc_Threads.ppt

Sincronização com Posix Threads
Sistemas Embutidos
2004
Motivação
Como compartilhar recursos?
Processo 0
Inicio
lê (in)
out = in
imprime (out)
Fim
Processo 1
Inicio
lê (in)
out = in
imprime (out)
Fim
Revisão de Conceitos
 Condição de corrida
Conjunto de eventos que levam a resultados não
determinísticos
 Região Crítica
Parte do código que implementa o acesso a um
recurso compartilhado
 Exclusão mútua
Mecanismo que impede o uso simultâneo de um
recurso compartilhado
const n=50;
var t: integer;
Um problema
procedure total;
var count:integer;
begin
for count = 1 to n do
t= t + 1
end;
A: Ra  t
RaRa+1
begin
B: t  49 Rb49
t=0;
A: tRa
parbegin
B: Rbt
total; A: t50
total; B: RbRb+1 t2
parend;
write ( t );
end.
t=0 Ra=1
t=49 Rb=49
 t=1
 Rb=1
 t=50
 t=2
Semáforos
 Solução proposta por Dijkstra em 1965
 Principio básico:
um processo é suspenso enquanto não obtém
permissão para executar uma RC e é “ acordado”
através de um sinal
 Para enviar um sinal via semáforo s o processo
executa uma primitiva signal(s) e para receber um
sinal via semáforo s o processo executa um primitiva
wait(s)
Threads
Modelo
MultiThread
Modelo de Processo
(únicoThread)
Bloco de
controle de
processo
Thread
Thread
Thread
Bloco do
controle
Thread
Bloco do
controle
Thread
Bloco do
controle
Thread
Bloco de
controle de
processo
Pilha
Usuário
Pilha
Usuário
Pilha
Usuário
Espaço de
endereçamento
do usuário
Pilha
Kernel
Pilha
Kernel
Pilha
Kernel
Pilha
Usuário
Espaço de
Pilha
endereçamento
Kernel
do usuário
Threads de Usuário
Escalonamento e sincronização não passam pelo kernel
Escalonamento é determinado pelo aplicativo
Podem ser usadas em qualquer S.O.
Chamadas ao sistema bloqueiam o processo
Não pode fazer uso de mais de um processador
Threads de Kernel
Threads do mesmo processo podem ser executados
simultaneamente em processadores diferentes
 O bloqueio de um thread não bloqueia as demais
threads de um processo
Escalonamento e sincronização são muito custosos
LightWeightProcess
Criação de threads é feita em modo usuário
A maior parte do escalonamento e sincronização
acontece em modo usuário
Os threads em modo usuário são mapeadas num
número possivelmente menor de threads do kernel
Comunicação entre Threads
• compartilhamento de recursos
• espaço de endereçamento de memória
compartilhado
• técnicas de sincronização semelhante as
utilizadas em processos
Threads no Linux
• Implementação no kernel através da função
clone()
• Utilização da biblioteca Pthreads para garantir a
portabilidade
• Em um programa em C, incluir o cabeçalho
pthread.h e acrescentar –lpthread na linkedição.
Pthreads
pthread_create(*t, *a, rotina, arg);
t é um ponteiro para uma variável do tipo pthread_t que
a é um ponteiro para os atributos. Os atributos são
armazenados em uma variável do tipo pthread_attr_t.
Um valor NULL indica o uso de valores default. Para
detalhes veja pthread_attr_init(3)
rotina é o nome (ponteiro) para a função que será
executada.
arg é um void * que é passado como argumento para
rotina.
Pthreads
• A nova thread é disparada
imediatamente e termina no retorno da
função ou pela chamada da função
pthread_exit(*ret)
• O argumento ret aponta uma variável
que armazenará o valor de retorno.
• Já que pthread_exit nunca retorna, é de
certa forma o equivalente à função exit.
Pthreads
pthread_join(pthread_t id, void **return);
pthread_detach(id );
id é identificação da thread
return é o valor de retorno (pode ser NULL)
Pthreads - Sincronização
Mutex
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex
Variáveis de condição
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t
*mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
volatile double pi = 0.0;
pthread_mutex_t pi_lock;
volatile double intervals;
Ex. Calculo de Pi
int main(int argc, char **argv)
void *process(void *arg)
{
{
pthread_t thread0, thread1;
void * retval;
double width, localsum;
intervals = atoi(argv[1]); //intervalos
int i;
pthread_mutex_init(&pi_lock, NULL);
int iproc = (*((char *) arg) - ’0’);
if (pthread_create(&thread0, NULL, process, "0") ||
width = 1.0 / intervals;
pthread_create(&thread1, NULL, process, "1"))
localsum = 0;
{
for(i = iproc; i < intervals; i += 2) fprintf(stderr, "%s: cannot make thread\n", argv[0]);
{
exit(1);
register double x = (i + 0.5) * width;}
if (pthread_join(thread0, &retval) ||
localsum += 4.0 / (1.0 + x * x);
pthread_join(thread1, &retval))
}
{
localsum *= width;
// Lock & Unlock before accessing PIfprintf(stderr, "%s: thread join failed\n", argv[0]);
exit(1);
pthread_mutex_lock(&pi_lock);
}
pi += localsum;
printf("Estimation of pi is %f\n", pi);
pthread_mutex_unlock(&pi_lock); exit(0);
return(NULL);
Sincronização de Threads
Comunicação Serial
Características
• Um “servidor” pode receber/enviar
mensagens através de uma porta serial
RS485.
• A comunicação com um “cliente” só pode
acontecer quando a linha estiver livre
• O acesso ao meio serial deve ser controlado
por mutex
Problema
Servidor
Mensagens não
transmitidas ao Servidor
EnviaMsg
GERENTE
Poll
armazenamento
Contagem
ConvL
RespServ
Ocorrências de queda ou
retorno de fase
Fast Select
Servidor
Caso servidor não esteja
disponível
Programa principal
int main(int argc, char **argv){
pthread_t tp;
pthread_mutex_t lock;
config_serial();
pthread_mutex_init(&lock,NULL);
pthread_mutex_lock(&lock);
//obtém lock
pthread_mutex_init(&serial,NULL);
if (pthread_create(&tp, NULL,(void *)Poll, NULL) ) {
perror("Criacao da thread Poll");
exit(1);
}
while(1);
}
Tratamento de relógio
//Inicializa Timer
void init_timer(){
struct sigaction timer;
timer.sa_handler = handler_timer;
timer.sa_flags = SA_RESTART;
sigemptyset(&timer.sa_mask);
sigaction(SIGALRM,&timer,
NULL);
}
void handler_timer (){
int p;
p =0;
trata_relogio(p);
}
void trata_relogio(int p){
struct itimerval valor,ovalor;
if (p == 1){ // liga timer
valor.it_interval.tv_sec = 30;
pthread_mutex_lock(&lock);
}else{ // desliga timer
valor.it_interval.tv_sec = 0;
valor.it_value.tv_sec=0;
pthread_mutex_unlock(&lock);
}
valor.it_interval.tv_usec = 0;
valor.it_value = valor.it_interval;
setitimer (ITIMER_REAL, &valor,0);
}
Rotina Poll
void Poll() {
estado = INICIO_POLL;
while (1) {
switch (estado){
case INICIO_POLL:
pthread_mutex_lock(&lock); // fica preso
pthread_mutex_lock(&serial); // obtém meio serial
•
•
•
case FIM_POLL:
pthread_mutex_unlock(&serial); // libera meio serial
trata_relogio(1);
}
O que aconteceria ...
• se durante um ciclo, a thread poll atualizasse
uma tabela compartilhada na memória?
• se após o ciclo, esta tabela fosse atualizada no
disco?
• Se durante o ciclo, uma outra thread retirasse
um elemento da tabela?
CUIDADO COM A ORDEM DOS SEMÀFOROS:
SUJEITO A DEADLOCK
Exercício
Altere o programa anterior para que os dados
obtidos no ciclo de Poll sejam armazenados em
um arquivo. Periodicamente este arquivo é lido
por um outro thread e enviado via internet para
um servidor remoto (simplesmente utilize uma
função Envia( ) admitindo que está funcionando
corretamente)