unix process
Post on 27-Jun-2015
320 Views
Preview:
DESCRIPTION
TRANSCRIPT
Unix Process
Todos vocês já usaram...
Tudo isso estásendo executado
através de um
PROCESSO
Um pouco de história
- A programação unix existe desde 1970
- Foi inventado nos laboratórios Bell (Bell labs)
- Os conceitos e técnicas de programação unixnão são novidades. Essas técnicas vão além daslinguagens de programação.
- Essas técnicas não são modificadas há décadas
Processos
- Quem sabe a diferença entre userland e kernel?
Processos
Kernel- É a camada que está em cima do hardware. Ou seja, é o homem do meio entre toda interação que acontece entre a userland e o hardware
- Essas interações incluem coisas como:. Ler/Escrever no diretório de arquivos. Enviar arquivos pela rede. Alocar memória. Tocar música através dos auto-falantes
Devido ao seu poder, nenhum programa possui acesso direto ao Kernel
Processos
Userland- É onde todos os seus programas são executados- Seu programa pode fazer muita coisa sem precisar do kernel:
. Realizar operações matemáticas
. Realizar operações com strings
. Controle de fluxo através de operações lógicas
Mas se você quiser fazer várias coisas legais terá que utilizar o kernel
Processos
System call
- Qualquer comunicação entre o kernel e userland é feita através de system calls
- É a interface que conecta o kernel e a userland
- Define as interações que são permitidas entre o seu programa e o hardware
Processos
Process identifier (pid)
- Todo processo possui um identificador único- Nada mais é que um número sequencial. É assim que o kernel vê o seu processo: como um número
>> puts Process.pid || $$ #system call: getpid
- Não está ligado a nenhum aspecto do conteúdo do processo.- Pode ser entendido por qualquer linguagem de programação
Processos
Parents process (ppid)- Todo processo rodando no seu sistema possui um pai
- O processo pai é o processo que invocou outro determinado processo.
>> puts Process.ppid #system call: getppid
- O ppid pode ser importante quando estivermos detectando processos deamons
Processos
File descriptors
- Representa arquivos abertos- Em unix tudo é arquivo!
. Isso significa que dispositivos são tratados como arquivo, sockets e pipes são tratados como arquivos e arquivos são tratados como arquivos!
- Qualquer momento que você abrir um recurso, é atribuido um número de file descriptor a esse recurso
Processos
File descriptors- Não são compartilhados entre processos que não estão relacionados
- Eles vivem e morrem com o processo que eles estão ligados>> file = File.open(“path/to/the/file”)>> file.fileno=> 3
- É através do fileno que o kernel consegue manter o controle dos recursos que seu processo está utilizando
Processos
File descriptors- Apenas recursos abertos possuem file descriptors- Todo processo unix vem com três recursos abertos
. STDIN
. STDOUT
. STDERR
- Existe uma limitação de 1024 file descriptors abertos por processo
Processos
Environment variables
- São pares chave-valor que possuem dados para os processos
- Todo processo herda variáveis de ambiente de seus pais
- São definidas por processo e são globais para cada processo
$ MESS=‘teste’ ruby -e “puts ENV[‘MESS’]”
Processos
Argumentos
- ARGV: argument vector
- É uma forma de passar argumentos para os processos
p ARGV$ ruby argv.rb foo bar -ba[“foo”, “bar”, “-ba”]
Processos
Possuem nome
- Todo processo possue um nome e esse nome pode ser mudado durante seu runtime
>> puts $PROGRAM_NAME
- É uma forma eficiente de comunicar a tarefa que está sendo desenvolvida
=> irb
Processos
Possuem um código de finalização
- Todo processo, ao finalizar, possui um código
- É um número entre 0-255 que denota se o processo finalizou com sucesso ou não
- A finalização com um código 0 indica que tudo ocorreu como esperado
- Mas... Os outros códigos são utilizados como forma de comunicação
ProccessCAN use the
FORK
Processos
Fork- É um dos conceitos mais poderosos da programação unix
- Permite que um processo em execução crie outro processo, utilizando recursos de programação para isso
- O novo processo criado é uma cópia exata do processo original
Processos
Fork- O processo filho herda uma cópia de toda memória usada pelo processo pai bem como todos os file descriptors
Recapitulando...
- O ppid do processo filho é o pid do processo pai.- O processo filho possui o mesmo mapa de file descriptors que o processo pai
Processos
Forkif fork
puts “entrando no if”else
puts “entrando no else”end
=> entrando no if=> entrando no else
WTF???- O método fork retorna duas vezes (ele cria outro processo, lembra??)- Retorna uma vez no processo pai e uma vez no processo filho
Processos
Fork
puts “processo pai #{Process.pid}”if fork
puts “entrando no if atraves do processo #{Process.pid}”else
puts “entrando no else atraves do processo #{Process.pid}”end
=> processo pai 2000=> entrando no if atraves do processo 2000=> entrando no else atraves do processo 2010
- O processo filho é finalizado após executar o código que está no else- O retorno do fork no processo pai é o pid do filho. Já no processo filho o fork retorna nil
Processos
Fork
Multicore Programming
- Não é garantido de ser distribuido através das CPUs disponíveis. Depende do SO
- É preciso ser feito com cuidado!
# system call => fork
Processos
Processos orfãos
fork do5.times do
sleep 1puts “Eu sou orfão!”
endend
abort “Parent process died ...”
- O que acontece com um processo filho quando seu pai morre?
. Nada!
Processos
CoW Friendly
- Copiar toda memória na hora do fork pode ser considerado um overhead
- Sistemas Unix modernos empregam uma técnica chamada Copy on Write para evitar o overhead
- A cópia da memória é evitada até que alguma escrita seja necessária
- Dessa forma o processo pai e o processo filho compartilham a memória até uma escrita ser realizada pelo processo filho
Processos
CoW Friendlyarr = [1,2,4]
fork do# nesse momento não há copia de memória# a leitura é feita de forma compartilhadaputs arr
end
fork do# Ao modificar o array uma cópia do array precisa ser feita# para o processo filhoarr << 4
end
- Isso mostra que realizar um fork é rápido
- Os processos filhos possuem uma cópia dos dados modificados. O resto pode ser compartilhado
Processos
CoW Friendly
- MRI não é CoW friendly. O garbage collector utiliza um algoritmo ‘mark-and-sweep’ que não é compatível com cow
. O algoritmo realiza uma iteração por todo objeto existente marcando se o mesmo deve ser coletado ou não
. Dessa forma, quando o garbage collector rodar toda memória sera copiada para o processo filho
Processos
Podem esperar- Realizar um fork e não esperar o resultado é interessante para tarefas assincronas
message = “Opa, bão?”recipient = “rodrigo.diley@dito.com.br”
fork doStatsCollector.record message, recipient
end
#continua o envio da mensagem
- Mas em alguns outros casos você quer manter o controle sobre seus processos filhos
Processos
Podem esperar
fork do5.times do
sleep 1puts “Eu sou orfão!”
endend
- Basta utilizar em ruby: Process.wait
Process.waitabort “Processo pai morreu ...”
=> “Eu sou orfão!”=> “Eu sou orfão!”=> “Eu sou orfão!”=> “Eu sou orfão!”=> “Eu sou orfão!”=> “Processo pai morreu ...”
Podem esperar
- Process.wait
Processos
. É uma chamada bloqueante que faz o processo pai esperar por um de seus filhos terminar a execução
. É você que precisa saber qual processo está sendo terminado. Process.wait retorna o pid do processo filho
Processos
Podem esperar
- Condições de corrida. O que acontece quando um processo pai demora para realizar a chamada ao metodo wait?
. O Kernel coloca todas as informações de exit dos processos filhos em uma fila!
. Se Process.wait for chamado e não existir processo filho será lançada uma exception
Processos
Zombieee
- É sempre bom limpar os processos filhos
- O Kernel guarda informações de todos os processos filhos em um fila, estão lembrados?
- Se nós não retirarmos ela de lá, quem irá?NINGUEM
- Estamos gastando mal os recursos do Kernel
Processos
Zombieee
message = “Opa, bão?”recipient = “rodrigo.diley@dito.com.br”
pid = fork doStatsCollector.record message, recipient
end
Process.detach(pid)#continua o envio da mensagem
- Arrumando nosso exemplo
- Basicamente, Process.detach dispara uma nova thread que terá como terefa esperar o processo filho terminar
Processos
Zombieee- Todo processo filho que termina e não possui seus status coletado é considerado zombie
pid = fork { sleep(1) }puts pidsleep
$ ps -ho pid,state -p [pid do processo]
- O status impresso será z ou Z+
Processos
Recebem sinais
- Process.wait é uma chamada bloqueante- Como esperar por processos filhos em processos pais que estão sempre ocupados?
. Basta trabalhar com sinais!
. CHLD é o sinal que o kernel envia para o processo pai indicando que um processo filho foi finalizado
Processos
Recebem sinais
child_process = 3dead_process = 0child_process.times do
fork dosleep 3
endend
trap(:CHLD) dowhile pid = Process.wait(-1, Process::WNOHANG)
puts piddead_process += 1exit if dead_process == child_process
endend
loop do (Math.sqrt(rand(44)) ** 8).floorsleep 1
end
Processos
Recebem sinais
- É uma forma de comunicação assincrona
- Quando um processo recebe um sinal do Kernel as seguintes ações podem ser tomadas:
. Ignorar
. Realizar algum comportamento específico
. Realizar o comportamento padrão
Processos
Recebem sinais
- Os sinais são enviados através do Kernel
- Basicamente, o Kernel é o middleman utilizado pelos processos para enviarem sinais uns aos outros
ComputadorLIGADO rodando
task remotaNUNCA MAIS
Processos
Recebem sinais
- Se sua tarefa já estiver rodando em um console basta enviar o sinal de stop para que a tarefa seja interrompida
- Após sua interrupção basta colocá-la para rodar em background através do comando bg
- Basta remover o vínculo com o terminal através do comando disown
Processos
Podem se comunicar
- Existem algumas formas de realizar IPC (Inter-process communication)
. Pipe
. Sockets
Processos
Podem se comunicar- Pipe
. É um caminho de mão única de fluxo de dados
reader, writer = IO.pipe => [#<IO:fd 5>, #<IO:fd 6>]writer.write(“Galo doido não perde em casa”)writer.close
puts reader.read
=> “Galo doido não perde em casa”
. É um stream de dados!
Processos
Podem se comunicar- Pipe
. É um recurso compartilhado como qualquer outro
reader, writer = IO.pipe => [#<IO:fd 5>, #<IO:fd 6>]
fork doreader.close10.times do
#trabalhando...writer.puts “Quase acabando”
endend
writer.closewhile message = reader.gets
$stdout.puts messageend
Processos
Podem se comunicar- Sockets. Pode ser um socket unix, para comunicaçãolocal. Pode ser um socket tcp, para comunicaçãoremota
- Outra possível solução seria RPC
Processos
Deamon- São processos que rodam em background e que não estão ligados a nenhum terminal controlado pelo usuário
- Tem um processo deamon que é muito importante para o sistema operacional
. É o pai de todos. É o processo chamado init, seu ppid é 0 e o seu pid é 1
Processos
Deamon
- Process group e session group
$ git log | grep shipped | less
- Todo sinal enviado para o pai de um process group é encaminhado para os filhos
- Todo sinal encaminhado para um session group é encaminhado para os processos que fazem parte desse grupo
OBRIGADO!
@sergiohenriquesergio.miranda@dito.com.br
top related