1 / 56

Programação Avançada Processos, Threads e IPC

Programação Avançada Processos, Threads e IPC. Prof. Natalia Castro Fernandes Mestrado em Telecomunicações – UFF 2º semestre/2012. Introdução. Processos Threads IPC – Interprocess Communication Memória Compartilhada Sockets Pipes. Processos. Processo Programa em execução

Download Presentation

Programação Avançada Processos, Threads e IPC

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programação AvançadaProcessos, Threads e IPC Prof. Natalia Castro Fernandes Mestrado em Telecomunicações – UFF 2º semestre/2012

  2. Introdução • Processos • Threads • IPC – Interprocess Communication • Memória Compartilhada • Sockets • Pipes

  3. Processos • Processo • Programa em execução • Execução sequencial • Inclui: • Contador de programa • Pilha • Seção de dados

  4. O processo • Atividade atual, incluindo o contador de programa e os registradores de processo • Contém múltiplas partes • Pilha com dados temporários • Parâmetros de funções, endereço de retorno, variáveis locais ? • Heap • Memória alocada dinamicamente • Memória • Seção de dados • Contém variáveis globais • Código, também chamado de seção de texto

  5. Processos • Programa x processo • Programa é passivo • Processo é ativo • O programa se torna um processo quando é carregado na memória Usuário Execute A Sistema Operacional Busca programa no disco Processo é criado! Disco Carrega programa na memória Memória A A

  6. Criando processos com o fork #include <sys/types.h> #include <studio.h> #include <unistd.h> int main() { pid_t pid; /* fork anotherprocess */ pid = fork(); if (pid < 0) { /* erroroccurred */ fprintf(stderr, "Fork Failed"); return 1; } elseif (pid == 0) { /* childprocess */ execlp("/bin/ls", "ls", NULL); } else { /* parentprocess */ /* parentwill wait for thechild */ wait (NULL); printf ("Child Complete"); } return 0; } Exemplos em Python: teste_fork3.py até teste_fork7.py Atenção!!!!! O fork só funciona em Linux para Python

  7. Árvore de processos

  8. Finalização de processos • Processo executa a sua última linha e pede ao sistema operacional para deletá-lo (exit) • Recursos do processos são desalocados pelo sistema operacional • Processo pai pode terminar a execução de um processo filho (abort) • Exemplos de motivação • Processo filho excedeu os recursos alocados • Tarefa passada ao filho não é mais necessária • Processo pai está sendo finalizado, e alguns sistemas operacionais não permitem que o filho continue executando após o pai ter sido finalizado • Finalização em cascata

  9. Threads • Threads são processos leves • Diferentes tarefas da aplicação podem ser implementadas como threads separados • Aplicável apenas às tarefas que possam ser paralelizadas • Exemplos: • Atualizar o display • Buscar dados • Verificar correção ortográfica

  10. Motivação • A criação de processos é muito custosa • Criação de threads é mais simples • Vantagens do uso de threads • Simplificação do código • Aumento da eficiência

  11. Processos mono e multithreads

  12. Benefícios • Melhora o tempo de resposta • Programa continua executando mesmo que algum thread seja bloqueado (thread no espaço de kernel) • Compartilhamento por padrão dos recursos do processo • Não precisa de técnicas para criar uma memória compartilhada • É mais simples criar um thread do que um processo • Não precisa alocar novos recursos e é fácil trocar contexto entre threads • Aumenta o paralelismo • Em máquinas com multiprocessamento

  13. Programação com múltiplos cores • Sistemas com múltiplos cores impulsionam novas formas de programar • Maior eficiência na execução de programas • Contudo, existem algumas dificuldades É possível paralelizar? As tarefas paralelizáveis tem a mesma importância? Quais conjuntos de dados pertencem a cada thread? Se duas threads usam dados dependentes, como sincronizar o acesso? Como depurar o processo, se existem múltiplos caminhos de execução?

  14. Threads • Exemplos • Ex_sem_thread.py • Ex_sem_thread_processo.py • Ex_thread.py • Ex_threadv2.py • Ex_thread_mais_legal.py • Ex_thread_mais_legal_completo.py • Ex_legal_final.py

  15. Comunicação interprocessos • Processos em um sistema podem ser independentes ou cooperativos • Processos cooperativos podem afetar ou serem afetados por outros processos • Processos independentes não podem afetar ou serem afetados pela execução de outro processo • Razões para cooperação interprocessos • Compartilhamento de dados • Aumento da velocidade de computação • Modularidade • Conveniência

  16. Comunicação interprocessos • Cooperação entre processos depende da interprocess communication(IPC) • Dois modelos de IPC • Memória compartilhada • Troca de mensagens

  17. Modelos de comunicação Memória compartilhada Envio de mensagens

  18. Sincronização • Envio de mensagens pode ser tanto blocante quanto não-blocante • Operação blocante é considerada síncrona • O send blocante bloqueia o emissor até que a mensagem seja recebida • O receive blocante bloqueia o receptor até que a mensagem esteja disponível • Operação não-blocante é considerada assíncrona • O emissor envia a mensagem e continua • O receptor recebe uma mensagem válida ou nulo

  19. Exemplos em Python • Compartilhamento de variáveis • shared_mem.py a shared_memv3.py • OBS: • Multiprocessing – API para processos cooperativos • Queue() – Cria fila compartilhada • put(), get() • Process(codigo do novo processo, argumentos) • start(), is_alive()

  20. Exemplos em Python • Compartilhamento de variáveis • shared_memv4.py • Multiprocessing • Value(tipo, valor) --- compartilhando um número • Array(tipo,lista) • Join() – Bloqueia o pai até o filho terminar • Shared_memv4b.py

  21. Comunicaçãoem sistemas cliente-servidor • Sockets • Pipes

  22. Sockets • Um socket é definido como um ponto de extremidade para a comunicação • Concatenação de IP e porta • Exemplo: • O socket 161.25.19.8:1625 se refere a porta 1625 no host 161.25.19.8 • A comunicação consiste de um par de sockets

  23. Exemplos em Python • Socket • Socket-client.py e socket-server.py • Socket-client-udp.py e socket-server-udp.py • Socket-client.py e socket-server-multiple.py

  24. Pipe • Atua como um condutor permitindo que dois processos se comuniquem • Pipes comuns permitem a comunicação em um estilo produtor-consumidor padrão • Funcionamento • O produtor escreve em uma ponta do pipe • O consumidor lê a saída na outra ponta • Portanto, pipes comuns são unidirecionais • Requerem relação de pai-filho entre processos comunicantes

  25. Pipes nomeados • Pipes nomeados são mais potentes que pipes comuns • Comunicação bidirecional • Não há necessidade de relação pai-filho • Pode ser usado por diversos processos • Disponível tanto em UNIX quanto em Windows

  26. Exemplos em Python • Pipe • Ex-pipe.py

  27. Acesso Concorrente • Acesso concorrente a um dado compartilhado pode resultar em inconsistência • Para manter a consistência, é preciso garantir uma execução ordenada dos processos cooperativos (que estão interagindo por meio de uma estrutura compartilhada) • Estudo da concorrência entre processos através de modelos • Exemplo: Produtor-consumidor

  28. Problema do Produtor-Consumidor • Produtor e consumidor são dois processos distintos • O produtor produz e coloca o produto no buffer • O consumidor consome produtos que estão no buffer • Consequências • O buffer passa a ser uma estrutura compartilhada • O produtor não pode colocar um produto em um buffer cheio • O consumidor não pode consumir um produto se o buffer estiver vazio • A variável compartilhada count pode ser usada para saber o número de elementos no momento dentro do buffer • Eventualmente, o count pode ser atualizado simultaneamente pelo produtor e pelo consumidor • Atualização não é uma tarefa atômica (indivisível)

  29. Produtor def produtor(): seed() global count i=0 while (True): sleep(random())#Tempo parasimular o processoproduzindo a informação if count<BUFFER_SIZE: buffer.append(str(i)) count = count +1 i=i+1 else: while (count>=BUFFER_SIZE): pass

  30. Consumidor def consumidor(): seed() global count while (True): if count>0: buffer.pop(0) count = count -1 sleep(random()) #Tempo parasimular o processoconsumindo a informação else: while(count<=0): pass

  31. Condição de disputa • O incremento do contador pode ser implementado da seguinte forma:register1 = counter register1 = register1 + 1 counter = register1 • O decremento do contador, por sua vez, seria:register2 = counter register2 = register2 - 1 count = register2

  32. Condição de disputa • Suponha que, no momento, count=5 e que o produtor e o consumidor estão sendo executados: t0: produtor: register1 = counter {register1 = 5}t1: produtor: register1 = register1 + 1 {register1 = 6} t2: consumidor: register2 = counter {register2 = 5} t3: consumidor: register2 = register2 - 1 {register2 = 4} t4: produtor: counter = register1 {count = 6 } t5: consumidor: counter = register2 {count = 4}

  33. Condição de disputa • Definição • Situação em que várias tarefas acessam dados concorrentemente e o resultado da execução depende da ordem específica em que o acesso ocorre

  34. Condição de disputa • Solução para a condição de disputa: • Sincronização de processos • Proteção das seções críticas • Uma seção crítica (ou região crítica) é um trecho de código no qual a tarefa está alterando uma estrutura compartilhada (variáveis compartilhadas, tabelas, arquivos, etc.) • Dessa forma, se um processo entra na sua seção crítica, nenhum outro processo que compartilhe alguma estrutura pode ser autorizado a entrar na sua seção crítica

  35. Problema da seção crítica • Problema de como controlar o acesso às seções críticas de processos que compartilham dados • Ideia: Criar um protocolo de acesso • Processo pede autorização para entrar na seção crítica • Quando autorizado, processo executa seção crítica • Processo avisa que terminou sua seção crítica • Processo continua a sua execução

  36. Problema da seção crítica A entra na região crítica A deixa a região crítica Processo A B entra na região crítica B deixa a região crítica B tenta entrar na região crítica Processo B B bloqueado T1 T3 T4 T2

  37. Soluções para o problema da região crítica • Exclusão mútua • Nunca dois processos podem estar simultaneamente em suas regiões críticas • Progresso • Nenhum processo fora da sua região crítica pode bloquear outros processos • Espera limitada • Nenhum processo deve esperar eternamente para entrar em sua região crítica Nada pode ser afirmado sobre a velocidade de processamento ou sobre o número de CPUs disponíveis

  38. Revendo o Produtor-consumidor • Qual é/são as seções críticas do código? • Uso da variável count • Uso da variável buffer • Consumidor def consumidor(): seed() global count while (True): ifcount>0: buffer.pop(0) count = count -1 sleep(random()) #Tempo para simular o processo consumindo a informação else: while(count<=0): pass Seção crítica

  39. Revendo o Produtor-consumidor • Produtor def produtor(): seed() global count i=0 while (True): sleep(random())#Tempo para simular o processo produzindo a informação ifcount<BUFFER_SIZE: buffer.append(str(i)) count = count +1 i=i+1 else: while (count>=BUFFER_SIZE): pass Seção crítica

  40. Revendo o Produtor-consumidor if __name__ == '__main__': ###Programa principal print "Esse programa simula o problema do produtor-consumidor, utilizando uma lista compartilhada por n threads: os produtores e os consumidores" print "Está se utilizando o método da espera ocupada." count = 0 prod=20 #Numero de produtores cons= 20 #Numero de consumidores t=[1]*(prod+cons) #Inicio o número de threads for i in range(prod): t[i] = Thread(target=produtor, args=()) t[i].start() for i in range(prod,prod+cons): t[i] = Thread(target=consumidor, args=()) t[i].start() while (True): if (len(buffer) != count): print "ERRO!!!!, pois tamanho do buffer = %d e count = %d" % (len(buffer),count) sleep (0.1) if (len(buffer)>10): print "ERRO!!!!, pois o buffer estourou!!!" Seção crítica Seção crítica

  41. Revisão • Como proteger a seção crítica? • Enquanto um produtor está na seção crítica, nenhum outro produtor ou consumidor pode entrar na seção crítica • Seção crítica = seção aonde se atualiza ou se compara as variáveis compartilhadas • Enquanto um consumidor está na seção crítica, nenhum outro consumidor ou produtor pode entrar na seção crítica

  42. Semáforos • wait (S) { • while S <= 0 • ; // no-op • S--; • } • Signal e wait • Operações atômicas na modificação do semáforo • Modificam o valor do sinal Se S=1, decrementa S e pode entrar. Caso contrário, fica esperando em espera ocupada intsinal=1; wait(sinal); Regiãocrítica; signal (sinal); Espera ocupada = espera usando CPU • signal (S) { • S++; • }

  43. Deadlock • Deadlock – Acontece quando dois ou mais processos estão esperando por um evento que só poderia ser executado por um dos processos em espera • Exemplo • Imagine que S e Q são dois semáforos inicializados em 1 P0P1 wait (S); wait (Q); wait (Q); wait (S); . . . . . . signal (S); signal (Q); signal (Q); signal (S);

  44. Resolvendo o Produtor-Consumidor • Buffer de tamanho N • Semáforo mutex inicializado em 1 • Semáforo full inicializado em 0 • Semáforo empty inicializado em N Controla o acesso ao buffer Controla o número de espaços ocupados no buffer Controla o número de espaços vazios no buffer

  45. Resolvendo o Produtor-Consumidor • Produtor do { // produce an item in nextp wait (empty); wait (mutex); // add the item to the buffer signal (mutex); signal (full); } while (TRUE); Espera ter um vazio para usar e usa Pede acesso ao buffer Não pode trocar a ordem! Libera o acesso ao buffer Aumenta o número de espaços ocupados

  46. Resolvendo o Produtor-Consumidor Espera ter um cheio para usar e usa • The structure of the consumer process do { wait (full); wait (mutex); // remove an item from buffer to nextc signal (mutex); signal (empty); // consume the item in nextc } while (TRUE); Pede acesso ao buffer Libera o acesso ao buffer Aumenta o número de espaços vazios

  47. Semáforos e Locks em Python • threading.Lock() • Retorna um objeto do tipo lock • Usa acquire() e release() • Uma vez que um thread dê um acquire, os demais threads que tentarem fazer o acquire ficarão bloqueados até que o thread dê um release • Apenas um é liberado e os demais, caso existam, ficam na fila • threading.RLock() • Semelhante ao Lock, mas um mesmo thread pode pedir o Rlock mais de uma vez sem se auto-bloquear. Contudo, o número de releases precisa ser igual ao número de acquires para liberar o Lock

  48. Exemplos em Python • Ex_threadv2.py • Ex-thread-lock.py • Ex-thread-lockv2.py • Ex-thread-lockv3.py • Ex-thread-lockv4.py

  49. Semáforos e Locks em Python • threading.Semaphore([value]) • Retorna um objeto do tipo semáforo • Recebe um valor inicial do contador e bloqueará apenas quando o número ficar negativo • Valor padrão do contador é 1 • threading.BoundedSemaphore([value]) • Semelhante ao Semaphore, mas garante que o valor inicial nunca será excedido. • Valor padrão do contador é 1

  50. Exemplos em Python • Ex-semaphore.py • Ex-semaphorev2.py • Ex-semaphorev3.py • Ex-semaphorev4.py • Ex-semaphorev5.py

More Related