O erro foi presumir que esses números eram PIDS, quando na verdade são TIDS (IDs de thread). Veja a função do Linux gettid (2). A leitura no clone (2) fornece muitos detalhes adicionais (e interessantes).
Eu executei o programa pstree -p 31872 que imprimia a seguinte saída:
ruby(31872)─┬─{ruby}(31906)
└─{ruby}(32372)
A página man do pstree diz:
Child threads of a process are found under the parent process and are shown with the process name in curly braces, e.g.
icecast2---13*[{icecast2}]
(O acima é exibido de forma diferente por causa da opção -p ausente, que desativa a compactação).
Executando o pstree 31872 sem -p:
ruby───2*[{ruby}]
Quando tento observar os PIDS usando ps , nenhum resultado é encontrado. No entanto, os pids existem em / proc.
Minha pergunta é: por que os threads têm pids diferentes? Eu esperaria que eles fossem o mesmo (31872) que o processo. O mesmo comportamento é observado ao executar o htop.
Threads são frequentemente processos diferentes. Pelo menos no Linux, um "thread" geralmente é um clone do processo que compartilha alguma memória com o processo pai.
No entanto, em alguns idiomas, os threads permanecem parte do processo principal porque são threads "verdes", que são simulados na linguagem VM. Java e python são famosos por isso.