Planos de execução de processos e prioridades

Ainda falando sobre processos, é importante saber que podemos controlar as tarefas que são executadas no shell. Esse controle, nada mais é do que suspender a execução de um processo e continuar a executá-lo depois.

Nesse post, vou falar sobre planos de execução de processos e prioridades.

Planos de execução

Planos de execução, são os modos em que um processo pode ser executado: em background ou foreground. Na sua vida de administrador de sistemas, você irá ouvir muito sobre isso!

No post que falei sobre processos, coloquei as definições de background e foreground (vou reaproveitar para usar aqui…):

Background – processos em background estão rodando em segundo plano, ou seja, não tem interação com o usuário, não exibem a execução no monitor e não prendem o terminal (permitem que o usuário inicialize outros processos).

Foreground – processos em foreground estão rodando em primeiro plano, ou seja, o comando é executado e prende o terminal. Nada poderá ser feito no terminal até que o processo termine.

Imagine que você está na empresa e precisa copiar um diretório que tem arquivos grandes. Como isso vai levar um certo tempo e você não quer o terminal preso, pode colocar o comando para rodar em background.

Por exemplo:

# cp -R /dumps /backup &

E o comando para colocar em background é apenas o ‘&‘ no final do comando.

Outro exemplo; podemos atualizar a base de dados do comando locate com um simples updatedb. Mas, dependendo de quanto tempo faz que você não executa esse comando, isso pode levar um tempo; daí, é interessante deixar esse comando rodando em background:

# updatedb &

Quando o shell inicializa um processo em background, nós temos uma linha similar a esta:

# updatedb &
[1] 2984

Essa linha, indica o número do job (entre colchetes) e o número do PID do processo. E para visualizar os processos que estão rodando em backgrond, utilizamos o comando jobs:

# jobs

Agora… vamos ver um outro exemplo. Imagine a seguinte situação: você iniciou o VI em background e precisa traze-lo para foreground (primeiro plano), fazer alguns ajustes e depois voltar o para background novamente.

Xi… confuso, né? Vamos por partes, como faria Jack:

1) Iniciar o processo em background:

# vi &
[1] 2020

Bem, iniciamos o processo em background! Temos o número do job [1]e o PID do processo 2020. Dessa forma, o terminal fica livre! Agora, vamos para o próximo passo, que é trazer o processo para o primeiro plano!

2) Trazer o processo para foreground. Aqui, temos que ter o número do jobs… Se não lembrar o número, executa o comando jobs:

# jobs
[1]+  Stopped                 vi

Temos o número do jobs! O status do processo é Stopped porque o vi é um processo interativo… não vai fazer nada se estiver em background 😉 !

Vamos trazer o processo para foreground; para isso utilizamos o comando fg:

# fg 1

Com isso, o VI irá abrir, e você poderá fazer os ajustes no arquivo.

3) Feito os ajustes no arquivo, é hora de colocar o processo para rodar em background novamente. Mas ai vem a pergunta: “Como colocar o processo em background sem parar o processo?”

Para isso, temos que primeiro colocar o processo para dormir com o comando CTRL+Z, que é o equivalente ao sinal SIGSTOP (-19); como estamos com o VI aberto; basta teclar CTRL+Z:

^Z

E ai, receberemos uma linha como abaixo:

[1]+  Stopped                 vi

4) Com o processo parado, podemos colocá-lo para rodar em background novamente; mas agora, não vamos usar o ‘&’ pois este só serve para iniciar um processo em background…
O comando que coloca em background um processo já iniciado é o bg:

# bg 1
[1]+ vi &

Pronto! Já temos o VI rodando em background novamente!

Para encerrar o processo, basta trazer o VI para foreground novamente e teclar ESC+ :q para sair!

Ahn, só lembrando, os comandos jobs, fg e bg são comandos internos do shell! Então, para saber mais sobre eles, basta fazer:

# man bash

Prioridade de processos

A prioridade de um processo, seria a gentileza (nice) que o kernel terá com um processo, reservando tempo de CPU e memória, sendo que, por padrão, cada processo iniciado possui uma prioridade.

Quando configuramos uma prioridade, estamos falando para o kernel tratar determinado processo com gentileza (prioridade alta) ou simplesmente nem tanta gentileza assim (prioridade baixa).

A prioridade padrão de um processo é 10 (equivale a 0 (zero)); e os comandos que utilizamos para controlar a prioridade são o nice e renice.

O comando nice é utilizado quando vamos iniciar um processo com uma determinada prioridade.

Já o comando renice, é usado quando vamos mudar a prioridade de um processo que já está rodando.

Números negativos, indicam alta prioridade, enquanto números positivos indicam prioridade baixa.
Vejam:

Tabela prioridade de processos

No exemplo, vamos iniciar um processo com prioridade alta:

# nice -n -15 find / -iname share

No comando acima, estamos pedindo para localizar arquivos ou diretórios com a palavra share, com prioridade -15.

A opção -n é utilizada pelo comando nice para ajustar a prioridade!

Para ver a prioridade, podemos ir em outro terminal e digitar:

# ps -lax
F   UID   PID  PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4     0  2146  2093   4 -15   2832   756 sync_b D<+  pts/0      0:02 find / -iname share

Onde a opção -l do comando ps é para listar em formato longo, ou seja, todas as informações; o comando, conforme colocado acima, não utiliza a opção u (a opção de listar os processos dos usuários).
E a gentileza que pedimos para o kernel tratar do processo, está na coluna NI.

Agora, para mudar a prioridade de um processo que está em execução, temos que ter o PID do processo. Por exemplo, vamos alterar a prioridade do processo cron:

# pgrep cron
2243

Com o PID em mãos, vamos alterar a prioridade do processo:

# renice -5 -p 2243
2243: old priority 0, new priority -5

Acima, ele mostra o processo, a prioridade antiga, 0, que é a prioridade padrão, e a nova prioridade que definimos!

É isso ai, pessoas… espero que esse post seja útil e ate a próxima! 🙂

Gerenciando processos no Linux

Processo é definido como porções de programas ou programa inteiro em funcionamento na memória do computador.

Mais especificadamente, do ponto de vista do sistema operacional é a estrutura responsável pela manutenção de todas as informações necessárias à execução de um programa.

De uma forma mais simples, tudo que estiver em execução na máquina é um processo, ou seja, o VI aberto é um processo, e até mesmo o shell onde você está logado no momento é um processo. Eu até costumo dizer que eu sou um processo :P.

Os processos são independentes, e cada processo individual possui uma identificação chamada PID (Process IDentification – identificação do processo). O PID é único e não pode ser repetido até uma nova reinicialização.

No diretório /proc, para cada processo em execução existe um subdiretório. Os nomes dos subdiretórios são os PIDs desse processos; os arquivos cmdline, environ e status dentro desses subdiretórios contém informações detalhadas sobre a execução desses processos:

cmdline – O que foi digitado para iniciar o processo (pode também ter sido iniciado através de um programa ou pelo kernel).

environ – Variáveis de Ambiente existentes no momento da execução do processo.

status – Dados sobre a execução do Processo (PID, status da execução do programa, memória consumida, memória executável, UID, GID, etc).

Antes de falar sobre os comandos que usamos para controlar os processos, vou falar sobre a sequência de execução de um processo.

Quando um processo está sendo executado, passa por várias fases:

Ready (Pronto)

Running (Executando)

Waiting (Aguardando)

Logo que um processo é iniciado, está no estado ready e fica aguardando sua fatia de tempo (slice time) de CPU para ser executado (running).

No estado running, o processo está efetivamente na CPU e ficará lá até sua fatia de tempo se esgotar, voltando assim, ao estado ready.

Existem momentos em que um processo precisa aguardar o os resultado de outros processos (leitura, escrita, chamadas de sistema, etc).

Quando o processo tenta efetuar alguma operação de entrada e saída, ele pode ser bloqueado se o periférico que ele está tentando acessar estiver ocupado e passar ao estado de waiting (espera), até ser liberado novamente (ready).

Processos

Classificando os processos

Quando estão em execução, os processos podem ser classificados em foreground e background.

Foreground – processos em foreground estão rodando em primeiro plano, ou seja, o comando é executado e prende o terminal. Nada poderá ser feito no terminal até que o processo termine.

Background – processos em background estão rodando em segundo plano, ou seja, não tem interação com o usuário, não exibem a execução no monitor e não prendem o terminal (permitem que o usuário inicialize outros processos).

Monitorando processos

Para obtermos informações sobre os processos, podemos verificar o diretório /proc; mas o comando ps é a principal ferramenta para monitoramento de processos. Podemos usá-lo para exibir o PID, o UID, a prioridade e o terminal de controle de processos.

Resumindo, o comando ps consulta o /proc, e lista as informações dos processos, só que de uma forma mais simples para que nós possamos entender.

Podemos obter uma visão geral dos processos em execução com o comando ps aux:

# ps aux

Onde:

a – all – todos os processos

u – processos dos usuários

x – processos internos que não são gerados por usuários que estejam usando o terminal

Quando digitamos o comando acima, vimos que a saída do comando ps aux é em colunas:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      1966  0.0  0.4   4932  1092 ?        Ss   08:55   0:00 /usr/sbin/sshd
root      1999  0.0  0.2   1576   528 tty2     Ss+  08:55   0:00 /sbin/getty 38400 tty2
root      2000  0.0  0.2   1572   528 tty3     Ss+  08:55   0:00 /sbin/getty 38400 tty3

Falando sobre as colunas:

✔ USER – Nome do usuário proprietário do processo

✔ PID – Código de identificação do processo

✔ %CPU – Porcentagem de recursos de que o processo está usando

✔ % MEM – Porcentagem de memória real que o processo está usando

✔ VSZ – Tamanho virtual do processo

✔ TTY – Identificador do terminal onde o processo está rodando

✔ RSS – Número de páginas na memória

✔ STAT – Estado atual do processo:

R – Running – Executando

S – Sleep – Dormindo; aqui, o processo está aguardando algum recurso, ou um processo se encerrar para continuar a ser executado

D – Died – Morto

Z – Zumbi – processo que deu erro e está tentando se destruir (ui! esse me lembra a volta dos mortos-vivos… =/)

T – Stopped – Parado ou interrompido

Os estados dos processos não mudam; porém, existe uma coisa chamada variação de um processo, que são as siglas que ficam ao lado do estado do processo! São elas:

< – Prioridade maior que a padrão

N – Prioridade menor que a padrão

+ – Processo em foreground

s – Processo líder de sessão (processo principal)

L – Indica que algumas páginas estão bloqueadas no kernel

✔ START – Horário em que o processo foi iniciado

✔ TIME – Tempo de CPU que o processo consumiu

✔ COMMAND – Nome do comando e seus argumentos

Agora que já sabemos como monitorar os processos, vou falar um pouco sobre os sinais que podemos enviar aos processos.

Sinais, nada mais são do que solicitações de interrupções em nível de processo. Por exemplo, quando você está executando um processo em linha de comando e tecla CTRL+C, está enviando um sinal de interrupção para o processo.

Alguns sinais que podem ser enviados aos processos são KILL, INT, TERM, HUP e QUIT.

HUP – utilizado para reiniciar um processo; geralmente usado por daemons, relê o arquivo de configuração e ajusta-se às alterações sem a necessidade de reinicialização.

INT – é um sinal enviado pelo terminal quando teclamos CTRL+C, e encerra a operação atual.

QUIT – é similar ao TERM, exceto pelo fato de gerar core dump (imagem da memória de um processo que pode ser usado para depuração).

KILL – é uma solicitação de destruição do processo (hum, isso parece grave!). Esse sinal não pode ser bloqueado ou ignorado; isto é, ele começou a destruir o processo… ele nem liga se você quer que ele pare com a destruição ou não!

TERM – é uma solicitação para terminar completamente a execução. Espera-se que o processo limpe seu estado e saia.

Ahn, os sinais acima, também são representados por números:

HUP = 1

INT = 2

QUIT = 3

KILL = 9

TERM = 15

O comando kill é utilizado para enviar sinais aos processos; pode enviar qualquer sinal, porém como padrão envia um

TERM. O comando kill pode ser usado por usuários comuns em seus próprios processos ou pelo superusuário em qualquer processo. Sua sintaxe é:

kill -SINAL PID

Onde:

-SINAL – a interrupção que será enviada ao processo; pode utilizar o nome do sinal ou o seu número

PID – Número de identificação do processo

Os sinais que mais utilizados são o -9 (KILL) e o 15 (TERM).

O -15, como já comentado anteriormente, é o sinal padrão e a forma educada de pedir para um processo parar. Mas as vezes isso não funciona, pois se o processo estiver trabalhando, não vai se encerrar…

Então, entra em ação o -9, que é o sinal matador, que não pergunta nem se o processo está sendo usado e já chuta ele da lista!

Bom, vamos ver um exemplo do comando kill. Mas antes, um comando que ajuda muito quando listagem do comando ps está longa, é o pgrep. É uma mistura do comando ps com o grep :D.

Exemplo, quero achar o PID do processo cron. Posso fazer assim:

# ps aux | grep cron
root      2633  1.0  0.2   3380   752 ?        Ss   20:01   0:00 /usr/sbin/cron

Ou então, assim:

# pgrep cron
2633

Bem, checamos que o processo está rodando, então vamos usar o kill; primeiro fazendo um teste com o -15:

# kill -15 2633

Depois, vamos ver se o cron aparece na lista:

# pgrep cron

Vejam que não aparece mais na lista! Isso quer dizer que o processo foi terminado!

Vamos ver novamente outro exemplo… agora com o processo do bash:

# pgrep bash
2425

Vamos usar o -15 de novo:

# kill -15 2425

Checando…

# pgrep bash
2425

Ui! Usamos o -15 e necas… o processo continua lá!

Vejam que usei o -15… e ele não mata pois tá te falando que ele está sendo usado!

Ou seja, se o processo está sendo usado, ele não é fechado com o -15, então terá que usar o -9:

# kill -9 2425

E ai, voces verão que volta para a tela de login novamente! (Adoro isso :P).

Só relembrando que 2425 é o número do PID que apareceu no pgrep.

Ah, existem mais sinais no Linux… para conhecer todos os sinais, consulte o man!

# man 7 signal

Bem, por enquanto é só, pessoal! No próximo post, vou comentar sobre os comandos que permitem deixar o processo rodando em primeiro e segundo plano, além de falar sobre os comandos que mudam a prioridade dos processos!

Até lá!