mac422/5753 sistemas operacionais - rede linux...
TRANSCRIPT
MAC422/5753Sistemas Operacionais
Prof. Marcel P. Jackowski
Aula #8
Sincronização: Semáforos, Barreiras e Monitores
Jantar dos FilósofosCinco filósofos que somente comem e pensam
Cada um deles precisa de 2 garfos para poder comer
Porém temos somente temos 5 garfos!
Este problema clássico ilustra a dificuldade de alocar recursos entre processos sem “deadlock” e “starvation”. 5 garfos, 5 filósofos
Solução inicialsemaphore fork[5] = {1,1,1,1,1};
/* PROCESSO FILÓSOFO i */void main(){ for(;;) { /* pensa */ wait(fork[i]); /* esquerda */ wait(fork[i+1 % 5]); /* direita */ /* come */ signal(fork[i+1 % 5]); signal(fork[i]); }}
O que acontece ?
Solução alternativa
Quebrar a dependência circular
Uma solução assimétrica
semaphore fork[5] = {1,1,1,1,1};
/* PROCESSO FILÓSOFO i=0..3 */void main(){ for(;;) { /* pensa */ wait(fork[i]); wait(fork[i+1 % 5]); /* come */ signal(fork[i+1 % 5]); signal(fork[i]); }}
/* PROCESSO FILÓSOFO i=4 */void main(){ for(;;) { /* pensa */ wait(fork[0]); wait(fork[4]); /* come */ signal(fork[4]); signal(fork[0]); }}
Filósofos pares e ímpares podem ter estratégias diferentes.
Segunda solução: limitar o número de filósofos
semaphore fork[5] = {1,1,1,1,1};semaphore chair = 4;
/* PROCESSO FILÓSOFO i */void main(){ for(;;) { /* pensa */ wait(chair); wait(fork[i]); wait(fork[i+1 % 5]); /* come */ signal(fork[i+1 % 5]); signal(fork[i]); signal(chair); }}
Leitores-Escritores
Acesso compartilhado à um banco de dados
Múltiplos processos tentando ler um item, e um ou mais processos tentando escrever
Ex: reservas aéreas
Solução inicial
/* PROCESSO ESCRITOR */void main(){ for(;;) { wait(mutex); /** ESCRITA **/ signal(mutex); }}
semaphore mutex = 1;
/* PROCESSO LEITOR */void main(){ for(;;) { wait(mutex); /** LEITURA **/ signal(mutex); }}
Exclusão mútua seletiva
Ao invés de garantir exclusão mútua para qualquer tipo de acesso, seguiremos as seguintes regras:
Quaisquer número de leitores podem ler simultaneamente
Somente um escritor é permitido por vez
Nenhum leitor pode ler enquanto um escritor escreve.
Solução 1int leitores = 0;semaphore mutex=1, escritor=1;
/* PROCESSO LEITOR */void main(){ for(;;) { wait(mutex); leitores++; if (leitores==1) wait(escritor); signal(mutex); /** LEITURA **/ wait(mutex); leitores--; if (leitores==0) signal(escritor); signal(mutex); }}
/* PROCESSO ESCRITOR */void main(){ for(;;) { wait(escritor); /** ESCRITA **/ signal(escritor); }}
Conclusões sobre semáforos
Ferramentas poderosas para garantir exclusão mútua e coordenação entre processos
Se usados corretamente, evitam “deadlock” e inanição (“starvation”)
Porém se wait(S) e signal(S) estiverem espalhados em vários processos pode ser tornar difícil usá-los corretamente
Um único processo operando de forma errônea pode culminar na falha de todo o processo de cooperação.
Semáforos em Linux
Linux: duas implementações POSIX e System V
POSIX: utilizado em threads
System V: processos e threads
Um pouco mais complicado
Semáforos usando System V IPC
Assim como segmentos de memória compartilhada e filas de mensagens (“message queues”), podemos criar conjuntos de semáforos
Instrumentos para gerir a coordenação entre processos
Normalmente associados com operações em recursos compartilhados.
Status do IPCipcs -<recurso>
Fornece informações sobre os recursos IPC do sistema operacional.
ipcs -m (memória compartilhada)
ipcs -s (semáforos)
ipcs -q (filas de mensagens)
ipcs -a (todos os recursos)
ipcrm [sem | shm | msg] <id> destrói um recurso IPC.
Alocaçãoint semget(key_t key, int nsems, int semflg)
key: identificador do semáforo.
IPC_PRIVATE cria um identificador único
nsems: número de semáforos no conjunto
semflg:
IPC_CREAT: cria um novo conjunto quando um valor de key é passado
IPC_EXCL: exclusive, usado em conjunto com IPC_CREAT, caso o segmento já exista, retorna erro
Mode Flags: flags de acesso 9 bits
Inicializaçãoint semctl(int semid, int semnum, int cmd, union semun arg)
semid: identificador retornado pelo semget
semnum: número do semáforo
cmd:
GETALL
GETNCNT
GETPID
GETVAL
GETZCNT
SETALL
SETVAL
Operaçõesint semop (int semid, struct sembuf *sops, unsigned nsops)
semid: identificador retornado pela operação semget
sem_op: -1 (wait), 1 (signal)
nsops: número de operações
struct sembuf { ushort sem_num; /* semaphore index */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */};
#define SHM_SIZE 4096#include <stdio.h>#include <sys/shm.h>#include <sys/stat.h>#include <sys/sem.h>#include <sys/types.h>#include <sys/ipc.h>
union semun {int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf;
};
int main(){ int shmid, semid; char* saddr; union semun arg; struct sembuf wait={0, -1, 0}; struct sembuf signal={0, 1, 0};
/* aloca memória compartilhada */ shmid= shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | S_IRUSR | S_IWUSR); /* aloca semáforo */
semid= semget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR); saddr= (char *)shmat(shmid, 0, 0);
/* inicialização */ arg.val=1; semctl(semid, 0, SETVAL, arg);
if (fork()==0) {//children saddr[0]=65; printf("Filho pegando semaforo\n"); if (semop(semid, &wait, 1) == -1) { perror("semop"); return 1; } printf("Filho na secao critica\n"); sleep(20); if (semop(semid, &signal, 1) == -1) { perror("semop"); return 1; } printf("Filho liberou semaforo\n"); return 0;}saddr[1]=66;sleep(2);printf("Pai esperando semaforo\n");if (semop(semid, &wait, 1) == -1) { perror(" semop"); return 1;}printf(" Pai na secao critica %s" , saddr);if (semop(semid, &signal, 1) == -1) { perror(" semop"); return 1;}printf("Pai liberou semaforo\n");shmctl(shmid, IPC_RMID, 0);return 0;
Barreiras
Mecanismo de sincronização dirigido à grupos de processos
Algumas aplicações são divididas em fase e têm como regra que nenhum processo pode avançar para a próxima fase até que todos os processos estejam prontos para fazê-lo
Isso pode ser conseguido por meio de uma barreira no final de cada fase
Quando uma barreira é alcançada o processo é bloqueado até que todos a alcancem.
Uso de barreiras
a) processos se aproximando de uma barreira
b) todos os processos, exceto um, bloqueados pela barreira
c) último processo chega, todos passam
Forma geral
process worker[ i = 1 to N ] {while (true) { /* código para implementar tarefa i */ /* espera por todas N tarefas completarem */ }}
Exemplo de barreira
semaphore p1=0, p2=0;
/* Processo 1 */void main(){ for(;;) { /* tarefa #1 */ signal(p1); wait(p2); }}
/* Processo 2 */void main(){ for(;;) { /* tarefa #2 */ signal(p2); wait(p1); }}
Tentativa com 3 processos
/* Processo 3 */void main(){ for(;;) { /* tarefa #3 */ signal(p3); wait(p1); wait(p2); }}
/* Processo 2 */void main(){ for(;;) { /* tarefa #2 */ signal(p2); wait(p1); wait(p3); }}
semaphore p1=0, p2=0, p3=0;
/* Processo 1 */void main(){ for(;;) { /* tarefa #1 */ signal(p1); wait(p2); wait(p3); }}
Exemplo com coordenador
semaphore aqui=0, p[2]={0,0};
/* Processo 1 */void main(){ for(;;) { /* tarefa #1 */ signal(aqui); wait(p[0]); }}
/* Processo 2 */void main(){ for(;;) { /* tarefa #2 */ signal(aqui); wait(p[1]); }}
/* Processo coordenador */void main(){ for(;;) { for(int i=0;i<2;i++) wait(aqui); /* colhe resultados */ for(int i=0;i<2;i++) signal(p[i]); }}
Monitores
13
Monitors
! Background: concurrent programming meets object-
oriented programming
! When concurrent programming became a big deal, object-
oriented programming too
! People started to think about ways to make concurrent
programming more structured
! Monitor: object with a set of monitor procedures
and only one thread may be active (i.e. running one
of the monitor procedures) at a time
Visão esquemática
14
Schematic view of a monitor
! Can think of a
monitor as one big
lock for a set of
operations/ methods
! In other words, a
language
implementation of
mutexes
Implementação
Variáveis de condição
Monitor com variáveis de condição
Semáforos e variáveis de condição
Produtor-consumidor usando monitor
Questão de semântica
Corrigindo a semântica
Monitores com Pthreads
Suporte à monitores: Java
Algumas linguagens suportam monitores. Ex: java
Java suporta threads de usuário e também permite que métodos sejam agrupados em classes
Palavra-chave synchronized à declaração de um método
Uma vez iniciado qualquer thread executando aquele método, a nenhum outro thread será permitido executar qualquer outro método synchronized naquela classe
Produtor-Consumidor
Exemplo de monitor
Tarefa
Modifique a solução do problema dos Leitores-Escritores para dar prioridade aos escritores.
Explique a função de cada semáforo utilizado na solução.
Implemente utilizar variáveis de condição e a biblioteca Pthreads.