Estados do processo Linux

89

No Linux, o que acontece com o estado de um processo quando ele precisa ler blocos de um disco? Está bloqueado? Em caso afirmativo, como outro processo é escolhido para execução?

Blair
fonte

Respostas:

86

Enquanto espera por read()ou write()para / de um retorno do descritor de arquivo, o processo será colocado em um tipo especial de hibernação, conhecido como "D" ou "Disk Sleep". Isso é especial, porque o processo não pode ser eliminado ou interrompido enquanto estiver em tal estado. Um processo esperando por um retorno de ioctl () também seria colocado em hibernação dessa maneira.

Uma exceção a isso é quando um arquivo (como um terminal ou outro dispositivo de caractere) é aberto no O_NONBLOCKmodo, passado quando é assumido que um dispositivo (como um modem) precisará de tempo para inicializar. No entanto, você indicou dispositivos de bloqueio em sua pergunta. Além disso, nunca experimentei um ioctl()que provavelmente bloquearia em um fd aberto no modo sem bloqueio (pelo menos não conscientemente).

Como outro processo é escolhido depende inteiramente do planejador que você está usando, bem como do que outros processos podem ter feito para modificar seus pesos dentro desse planejador.

Alguns programas de espaço do usuário, em certas circunstâncias, permanecem nesse estado para sempre, até serem reinicializados. Eles são normalmente agrupados com outros "zumbis", mas o termo não seria correto, pois eles não estão tecnicamente extintos.

Tim Post
fonte
1
"Um processo esperando por um retorno de ioctl () também seria colocado em hibernação dessa maneira". Acabei de matar meu processo de espaço de usuário esperando por um IOCTL de bloqueio, então isso não é verdade. A menos que eu não esteja entendendo
Hamzahfrq
Seria extremamente difícil cronometrar tal teste. Processos ininterruptos não podem ser eliminados; se você foi capaz de matá-lo, ele estava simplesmente bloqueando (o kernel não estava no meio de qualquer parte do ioctl e copiou qualquer resposta correspondente para o espaço do usuário no local que você passou (ou pelo menos não estava no meio da cópia)). O Linux também mudou muito desde 2009, quando este foi escrito; o fenômeno é muito menos observável como antes.
Tim Post
133

Quando um processo precisa buscar dados de um disco, ele efetivamente para de funcionar na CPU para permitir que outros processos sejam executados porque a operação pode levar muito tempo para ser concluída - pelo menos 5 ms de tempo de busca por um disco é comum, e 5 ms são 10 milhões Ciclos de CPU, uma eternidade do ponto de vista do programa!

Do ponto de vista do programador (também chamado de "no espaço do usuário"), isso é chamado de chamada de sistema de bloqueio . Se você chamar write(2)(que é um wrapper de libc fino em torno da chamada do sistema de mesmo nome), seu processo não para exatamente nesse limite; ele continua, no kernel, executando o código de chamada do sistema. Na maioria das vezes, ele vai até um driver de controlador de disco específico (nome do arquivo → sistema de arquivos / VFS → dispositivo de bloco → driver de dispositivo), onde um comando para buscar um bloco no disco é submetido ao hardware apropriado, que é muito operação rápida na maioria das vezes.

ENTÃO o processo é colocado no estado de hibernação (no espaço do kernel, o bloqueio é chamado de hibernação - nada é 'bloqueado' do ponto de vista do kernel). Ele será ativado assim que o hardware finalmente buscar os dados apropriados, então o processo será marcado como executável e será agendado. Eventualmente, o planejador executará o processo.

Finalmente, no espaço do usuário, a chamada do sistema de bloqueio retorna com o status e os dados adequados e o fluxo do programa continua.

É possível invocar a maioria das chamadas de sistema de E / S no modo sem bloqueio (consulte O_NONBLOCKem open(2)e fcntl(2)). Nesse caso, as chamadas do sistema retornam imediatamente e apenas relatam o envio da operação do disco. O programador terá que verificar explicitamente em um momento posterior se a operação foi concluída, com êxito ou não, e buscar seu resultado (por exemplo, com select(2)). Isso é chamado de programação assíncrona ou baseada em eventos.

A maioria das respostas aqui mencionando o estado D (que é chamado TASK_UNINTERRUPTIBLEnos nomes dos estados do Linux) está incorreta. O estado D é um modo de hibernação especial que só é acionado em um caminho de código de espaço do kernel, quando esse caminho de código não pode ser interrompido (porque seria muito complexo para programar), com a expectativa de que bloquearia apenas por um tempo curto. Eu acredito que a maioria dos "estados D" são realmente invisíveis; eles têm vida muito curta e não podem ser observados por ferramentas de amostragem como 'top'.

Você pode encontrar processos impossíveis de matar no estado D em algumas situações. NFS é famoso por isso, e eu o encontrei muitas vezes. Eu acho que há um conflito semântico entre alguns caminhos de código VFS, que assumem sempre alcançar os discos locais e detecção rápida de erros (em SATA, um tempo limite de erro seria em torno de alguns 100 ms), e NFS, que realmente busca dados da rede que é mais resiliente e tem recuperação lenta (um tempo limite de TCP de 300 segundos é comum). Leia este artigo para a solução interessante introduzida no Linux 2.6.25 com o TASK_KILLABLEestado. Antes desta era, havia um hack onde você poderia realmente enviar sinais para clientes de processo NFS enviando um SIGKILL para o thread do kernel rpciod, mas esqueça esse truque feio.…

zerodeux
fonte
2
+1 para a resposta detalhada, mas observe que esta discussão teve uma resposta aceita por quase dois anos. Clique no link "Perguntas" se quiser ajudar nas perguntas mais recentes. Bem-vindo ao Stack Overflow e obrigado por contribuir!
GargantuChet
20
Essa resposta é a única a mencionar o NFS, que em alguns ambientes é a explicação mais comum para processos no estado D. +1.
Pinko
14
Muito boa resposta, obrigado. Observe também que o processo entra no estado D enquanto espera pelas páginas que foram trocadas, portanto, um processo de thrashing ficará no estado D por um longo tempo.
cha0site
@zerodeux boa resposta, mas acho que seu esquema (nome do arquivo -> sistema de arquivos / VFS -> dispositivo de bloco -> driver do dispositivo) deve ser (nome do arquivo -> VFS -> sistema de arquivos (ext3) -> dispositivo de bloco -> driver do dispositivo)
c4f4t0r
1
Seria seguro assumir que o tempo gasto no kernel esperando por spinlocks (que pode ou não estar relacionado ao disco i / o) todos relatados como estado D em /proc/stat?
pavio de
8

Um processo realizando I / O será colocado no estado D (ininterrupta hibernação) , o que libera a CPU até que haja uma interrupção de hardware que diga à CPU para retornar à execução do programa. Veja man pspara os outros estados do processo.

Dependendo do seu kernel, existe um agendador de processos , que mantém o controle de uma fila de execução de processos prontos para execução. Ele, junto com um algoritmo de escalonamento, informa ao kernel qual processo atribuir a qual CPU. Existem processos do kernel e processos do usuário a serem considerados. Cada processo é alocado em uma fatia de tempo, que é uma parte do tempo da CPU que ele pode usar. Uma vez que o processo usa todo o seu intervalo de tempo, ele é marcado como expirado e recebe prioridade mais baixa no algoritmo de escalonamento.

No kernel 2.6 , há um escalonador de complexidade de tempo O (1) , portanto, não importa quantos processos você tenha em execução, ele atribuirá CPUs em tempo constante. Porém, é mais complicado, uma vez que o 2.6 introduziu a preempção e o balanceamento de carga da CPU não é um algoritmo fácil. Em qualquer caso, é eficiente e as CPUs não ficarão ociosas enquanto você espera pelo I / O.

user224579
fonte
3

Como já explicado por outros, os processos no estado "D" (ininterrupto sleep) são responsáveis ​​pelo travamento do processo ps. Para mim, isso aconteceu muitas vezes com o RedHat 6.xe com os diretórios home NFS montados automaticamente.

Para listar processos no estado D, você pode usar os seguintes comandos:

cd /proc
for i in [0-9]*;do echo -n "$i :";cat $i/status |grep ^State;done|grep D

Para saber o diretório atual do processo e, talvez, o disco NFS montado que apresenta problemas, você pode usar um comando semelhante ao exemplo a seguir (substitua 31134 pelo número do processo em espera):

# ls -l /proc/31134/cwd
lrwxrwxrwx 1 pippo users 0 Aug  2 16:25 /proc/31134/cwd -> /auto/pippo

Descobri que dar o comando umount com a opção -f (forçar) ao sistema de arquivos nfs montado relacionado foi capaz de despertar o processo de hibernação:

umount -f /auto/pippo

o sistema de arquivos não foi desmontado porque estava ocupado, mas o processo relacionado foi ativado e eu consegui resolver o problema sem reiniciar.

Valerio Di Giampietro
fonte
1

Assumindo que seu processo é um único thread e que você está usando o bloqueio de E / S, seu processo irá bloquear esperando a conclusão da E / S. O kernel escolherá outro processo para executar nesse ínterim com base na gentileza, prioridade, tempo da última execução, etc. Se não houver outros processos executáveis, o kernel não executará nenhum; em vez disso, ele dirá ao hardware que a máquina está ociosa (o que resultará em menor consumo de energia).

Os processos que estão aguardando a conclusão da E / S normalmente aparecem no estado D em, por exemplo, pse top.

Derobert
fonte
Iniciei vários processos usando cerca de 10% da memória total. Percebi que muitos deles estão no estado D. Isso é devido ao IO lento nesta máquina em particular? Digamos que eu tenha 9 processos, eles podem estar competindo por IO e muitos deles estão no estado D.
Kemin Zhou
@KeminZhou Comparado às velocidades da CPU, o I / O é muito lento - I / O até rápido. Um único processo pesado de E / S pode facilmente ocupar um disco magnético, até mesmo um SSD. 10 processos pesados ​​de E / S podem ocupar alguns.
derobert de
1

Sim, a tarefa é bloqueada na chamada de sistema read (). Outra tarefa que está pronta é executada, ou se nenhuma outra tarefa estiver pronta, a tarefa ociosa (para aquela CPU) é executada.

Uma leitura normal de bloqueio do disco faz com que a tarefa entre no estado "D" (como outros notaram). Essas tarefas contribuem para a média de carga, embora não estejam consumindo a CPU.

Alguns outros tipos de IO, especialmente ttys e rede, não se comportam da mesma forma - o processo termina no estado "S" e pode ser interrompido e não é contabilizado na média de carga.

MarkR
fonte
0

Sim, as tarefas que aguardam IO são bloqueadas e outras tarefas são executadas. A seleção da próxima tarefa é feita pelo agendador Linux .

Martin v. Löwis
fonte
0

Geralmente, o processo será bloqueado. Se a operação de leitura estiver em um descritor de arquivo marcado como sem bloqueio ou se o processo estiver usando E / S assíncrona, ele não bloqueará. Além disso, se o processo tiver outros threads que não estão bloqueados, eles podem continuar em execução.

A decisão de qual processo será executado em seguida cabe ao planejador no kernel.

Benno
fonte