Como renunciar todos os threads (e filhos) de um processo no Linux?

17

O Linux (ainda) não segue o padrão POSIX.1, que diz que renice em um processo afeta "todos os encadeamentos de escopo do sistema no processo", porque de acordo com os pthreads ( 7) doc "os tópicos não compartilham um valor interessante comum".

No entanto, às vezes, pode ser conveniente para renice "everything" relacionado a um determinado processo (um exemplo seria o processo filho do Apache e todos os seus threads). Então,

  • como posso renice all threads pertencer a um determinado processo?
  • como posso renice todos os processos filhos pertencentes a um determinado processo?

Estou procurando uma solução bastante fácil.

Eu sei que os grupos de processos às vezes podem ser úteis, mas nem sempre correspondem ao que desejo fazer: eles podem incluir um conjunto mais amplo ou diferente de processos.

Usar um cgroup gerenciado por systemd também pode ser útil, mas, mesmo que eu esteja interessado em ouvi-lo, estou procurando uma solução "padrão".

EDIT: também, man (7) pthreads diz que "todos os encadeamentos em um processo são colocados no mesmo grupo de encadeamento; todos os membros de um grupo de encadeamentos compartilham o mesmo PID". Então, é possível até renice algo que não tem seu próprio PID?

    
por Totor 06.07.2016 / 22:25

4 respostas

6

Diferença entre encadeamentos e processos

Questão importante no Linux, porque a documentação perpetua dúvidas (sobre os threads não terem seu próprio PID, por exemplo).

Observação: esta resposta explica o Linux tópicos precisamente.

Resumindo: o kernel somente manipula "entidades executáveis", isto é, algo que pode ser executado e programado . No kernel, essas entidades são chamadas de processos. Um thread, é apenas um tipo de processo que compartilha (pelo menos) espaço de memória e manipuladores de sinais com outro.

Todo processo desse tipo tem um identificador exclusivo em todo o sistema: o PID (ID do processo). Para os chamados threads, às vezes é chamado TID (Thread ID), mas do ponto de vista do sysadmin (e do kernel!), O TID e o PID são a mesma coisa (eles compartilham o mesmo namespace).

Como resultado, você pode renice each "thread" individualmente porque tem seu próprio PID 1 .

Localizando todos os PIDs para renice recursivamente

Precisamos obter os PIDs de todos os processos ("normal" ou "thread") que são descendentes (filhos ou no grupo de threads) do processo to-be-niced. Isso deve ser recursivo (considerando os filhos das crianças).

O

Anton Leontiev responde da seguinte maneira: todos os nomes de pastas em /proc/$PID/task/ são PIDs de segmentos contendo um arquivo children listando possíveis processos filhos.

No entanto, falta recursividade, então aqui está uma rápida & script de shell sujo para encontrá-los:

#!/bin/sh
[ "$#" -eq 1 -a -d "/proc/$1/task" ] || exit 1

PID_LIST=
findpids() {
        for pid in /proc/$1/task/* ; do
                pid="$(basename "$pid")"
                PID_LIST="$PID_LIST$pid "
                for cpid in $(cat /proc/$1/task/$pid/children) ; do
                        findpids $cpid
                done
        done
}

findpids $1
echo $PID_LIST

Se o processo PID 1234 for o que você deseja recursivamente bom, agora você pode fazer:

renice -n 15 -p $(/path/to/findchildren.sh 1234)

1 Observe que, para conformidade com POSIX, chamar getpid(2) dentro de um encadeamento não fornecerá o ID exclusivo (PID) do sistema dessa entidade executável, mas sim o PID do processo principal dentro do "grupo de threads". Você precisaria chamar gettid(2) . Consulte esta resposta para obter mais informações.

    
por 20.10.2016 / 05:44
13

Você pode usar /proc/$PID/task para encontrar todos os segmentos de um determinado processo, portanto, você pode usar

$ ls /proc/$PID/task | xargs renice $PRIO

para renice all threads pertencentes a um determinado processo.

Mesmo caminho /proc/$PID/task/$PID/children pode ser usado para encontrar todos os processos filhos (ou /proc/$PID/task/*/children se você quiser todos os processos filho de todos os segmentos de um determinado processo).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO
    
por 17.10.2016 / 08:10
4

Não devemos confundir o processo PID e o id do thread algum dia escrito TID ou no comando ps LPW. O comando s tem opções para exibir os encadeamentos e, em top ou htop , você alterna entre encadeamentos e processo pela letra H . Como dito anteriormente pelo @Totor, com o NPTL, que é a implementação atual com o kernel > 2.6, todos os threads têm o mesmo pid, mas eles têm um tid distinto. Você mostra todos os segmentos de um processo por:

$ ps -Ljf <pid>

Esses tid são os nomes dos diretórios em /proc/<pid>/task , e mesmo que renice (1) diga que seu argumento default é um pid quando aplicado a um pid ele renegará apenas o thread principal ( Este é um bug na implementação do Linux como escrito em setpriority (2) ), ele também pode ser aplicado a um tid e renova o thread. É por isso que a resposta de @Anton é válida.

Mas na maioria das vezes há uma maneira mais fácil de alcançar o resultado desejado, todos esses threads compartilham o mesmo pgid que é o pid do líder do grupo; você pode renunciar por pgid emitindo:

$ renice -g <pgid>

Se você não quiser renunciar a algum outro processo que dependa do mesmo líder do grupo, você deve usar a receita do @ Anton:

$ renice <priority> $(ls -1 /proc/<pid>/task)

ou:

$renice <priority> $(ps --no-header -Lo tid <pid>)

Você também pode querer saber quais são os outros processos do mesmo grupo que o processo que deseja renegar, ou seja, os processos que compartilham o mesmo pgid. Você pode usar ps (1) , ps não permite selecionar processos pelo líder do grupo, mas você pode grep ps para fazer isso. Os processos com pgid 1908 serão dados pelo comando:

$ ps --no-header axo pid,pgid |sed -n '/^ *[0-9][0-9]*  *1908/s/[0-9][0-9]* *$//p'

ou se você preferir o awk para sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'
    
por 16.12.2017 / 23:12
-1

Aqui está um script meu:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>
    
por 20.08.2018 / 09:04