CI066 - Oficina de Programação
Notas de Aula # 08

Prof. Armando Luiz N. Delgado

1 Processos

Um processo é um programa em execução. Toda vez que o usuário digita um comando que executa um programa, o sistema UNIX cria um novo processo.

Mesmo que o usuário não esteja fazendo nada em particular, haverá pelo menos 1 (um) processo em execução: aquele associado ao shell iniciado quando o usuário logout no sistema.

Para a maioria dos processos, a entrada e saída está associada ao terminal:

1.1 Iniciando processos: foreground e background

Quando um programa utiliza a entrada e saída padrão, o usuário deve esperar pelo seu término antes de estar habilitado a executar outro comando ou programa por um dado terminal.

No entanto, alguns programas podem não usar ou necessitar de interação com o usuário. Por exemplo:

                 sort -k2 clientes >clientes_por_fone

Outros programas interagem com o usuário através de uma janela gráfica dedicada e distinta do emulador de terminal de onde foram iniciados. Exemplo disto é o gedit(1) quando executado em um ambiente X Windows.

Em ambos os cenários, não é necessário que o usuário espere pelo término do programa. Seria interessante que, enquanto o programa acima é executado, o usuário pudesse continuar a executar outras tarefas pelo mesmo terminal. Para fazer isto em UNIX, basta colocar o caracter & (ampersand) ao final da linha de comando (após quaisquer redirecionamentos, se houver):

                 sort -k2 clientes >clientes_por_fone &
                 gedit fones.txt &

Quando o shell espera pelo término de um programa antes de habilitar ao usuário a execução de um novo comando, dizemos que o programa está sendo executado em foreground.

Quando o shell inicia o programa, mas o deixa executar por si, retornando o controle do terminal ao usuário (o que acontece colocando-se & ao final da linha de comando), dizemos que o programa está sendo executado em background.

Um programa é candidato a ser executado em background quando ele não necessita entrada de dados do usuário através da entrada padrão (e.g., um editor como o vi(1)).

Pode-se executar vários programas em seqüência e em foreground usando-se apenas uma linha de comando. Basta separar cada comando por ; (ponto e vírgula). Assim, a linha de comando

               ls ~ ; cd ~ci066 ; wc -l LabNum7/fones.txt

é equivalente à

               ls ~
               cd ~ci066
               wc -l LabNum7/fones.txt

Da mesma forma, é possível executar vários programas em seqüência e em background usando-se apenas uma linha de comando. Basta separar cada comando por &. Assim, a linha de comando

   sort -k2 clientes >clientes_por_fone & wc -l fones.txt >num_fones &

é equivalente a:

           sort -k2 clientes >clientes_por_fone & 
           wc -l fones.txt >num_fones &

1.2 Monitoração de processos

A todo processo o sistema UNIX associa um número, denominado process ID ou simplesmente PID. Este identificador é usado pelo sistema operacional para controlar o acesso do programa aos recursos do computador, ou pelo usuário para controlar a execução do processo (e.g., abortar um processo caso se observe que ele não está trabalhando como devia).

Um comando pode disparar a execução de um único programa ou de um conjunto de 2 ou mais programas. Assim, usa-se o termo job para se referir a um comando executado pelo shell em background. A cada job (que pode gerar um ou mais processos) o shell associa um número denominado Job ID ou simplesmente JID.

Tanto o PID quanto o JID são exibidos pelo shell no momento em que se inicia a execução de um comando em background. Eles são exibidos em uma única linha na forma [JID]  PID. Por exemplo:

               sort -k2 clientes >clientes_por_fone & 
               [1] 1345

Quando um processo é iniciado em background termina, o shell exibe uma pequena mensagem na tela de onde o programa foi iniciado, indicando o JID e o comando:

               [1]    Done        sort -k2 clientes >clientes_por_fone

Quando um processo que necessita da entrada padrão é iniciado em background termina, o shell pára a execução do processo e exibe uma pequena mensagem na tela de onde o programa foi iniciado, indicando o JID, a condição de parada e o comando:

               vi teste.txt &
               [1]+  Stopped                 vi

Os principais comandos para monitoração de processos e jobs são:

1.3 Controle de Processos

Os principais comandos para controle de processos e jobs são:

Controle de Jobs

Quando um programa é iniciado em foreground, o usuário pode SUSPENDER (parar sem terminar) a execução digitando ^Z (Control-Z) pelo teclado. A mensagem [1]    Stopped        <comando> será exibida pelo shell. A partir deste momento, o usuário pode digitar qualquer comando pelo terminal, pois o programa está parado. Para retomar a execução do programa (em inglês, resume), dois comandos podem ser executados:

Para obter uma lista de todos os jobs em execução em uma determinada sessão de shell, basta usar o comando jobs, que mostra uma lista do tipo abaixo:

        [1]   Running                 emacs &
        [2]-  Running                 netscape &
        [3]+  Stopped                 vi

O sinal $+$ indica o JOB CORRENTE. O sinal $-$ indica o JOB ANTERIOR. Caso os comandos fg e bg sejam executados sem argumentos, eles são aplicados ao JOB CORRENTE.

Executando-se jobs -l, também será exibido o PID do processo principal do job:

        [1]   1245 Running                 emacs &
        [2]-  1247 Running                 netscape &
        [3]+  1256 Stopped (tty output)    vi

Caso se queira aplicar fg e bg em algum job que não o corrente (aquele com o sinal $+$ na lista de jobs), usa-se como argumento o número do job precedido por % (porcentagem):

        fg %1
        ^Z
        bg %1

Os argumentos para fg e bg podem ser na forma da tabela 1.


Tabela 1: Formas de especificação de jobs
Argumento Descrição
%nn job número nn
%nome comando que começa com nome
%?nome comando que contém com nome
% job corrente
%$+$ o mesmo que %
%$-$ job anterior


Controle de Processos

O comando ps(1) exibe na tela informação a respeito dos processos atualmente sendo executados no sistema. Conforme a opção, são mostrados apenas os processos do usuário ou de todos os usuários. A principal informação é o PID, o programa em execução e o nome do usuário.

O comando top(1) mostra os processos em ordem reversa de uso de CPU: os processos que mais usam a CPU aparecem no início da lista, juntamente com o proprietário do processo e com o PID, entre outras informações.

O comando kill(1) termina (mata) um processo. Seus argumentos são o PID ou JID, podendo haver mais que um ID na mesma linha de comando. Por exemplo:

            kill 1245
            kill 345 %3
            kill 2345 567 3456

Quando se executa um programa, ele pode ser interrompido com um ^C (Control-C). No entanto, isto pode não funcionar, sendo necessário então lançar mão de kill(1).

Quando se termina um processo com kill(1), o shell exibe uma mensagem do tipo

          [1]     Terminated           emacs

O efeito de um kill é fazer com que o programa seja terminado de forma suave e ordenada, sem prejuízo de eventuais arquivos que estejam sendo usados pelo processo.

Geralmente uma simples execução de kill é o suficiente para terminar um programa, mas há exceções. Neste caso, deve-se indicar um argumento opcional -9 que indica ao sistema que o processo deve ser terminado de modo forçado, sem dó nem piedade. Isto pode, eventualmente gerar problemas em arquivos usados pelo programa morto.

            kill -9 1245
            kill -KILL 345

Um usuário somente pode matar apenas os processos do qual ele é proprietário, isto é, processos que foram iniciados por ele mesmo.

Prioridades de Processos

Cada processo tem direito a utilizar os recursos do sistema. No entanto, Um processo pode ter associado uma prioridade mais alta ou mais baixa na utilização destes recursos.

Esta prioridade é definida com nice(1): nice -AJUSTE COMANDO, onde AJUSTE varia de -20 (maior prioridade) até 19 (menor prioridade).

      nice -15 ls           --> define prioridade mais baixa
      nice --12 netscape    --> aumenta a prioridade do processo

Somente o usuário root pode aumentar a prioridade de processos. Outros usuários podem apenas DIMINUIR a prioridade, usando para isto renice(1):

      renice 12 345        --> muda a prioridade do process com PID=345

1.4 Proprietários de Processos

UNIX diferencia dois tipos de USUÁRIO e GRUPO, para efeitos de definição de permissões de acesso a arquivos por um programa:

As permissões de acesso a arquivos por um processo são verificadas de acordo com a identificação EFETIVA de usuário e grupo.

No momento, nesta disciplina, o usuário e grupo efetivos são iguais aos usuário e grupo real, isto é, ao usuário que inicia o programa.



Armando Luiz Nicolini Delgado
2008-10-03