Thread#status e o ciclo de vida de uma thread

Prévia grátis 3 min de leitura

O que você já sabe, em duas frases

A aula "Threads e concorrência", do curso do nível intern Fundamentos de OS, cobriu processo contra thread e concorrência contra paralelismo. Também cobriu o GVL e por que ele é liberado durante I/O, Thread.new/.join, uma demo de condição de corrida corrigida com Mutex#synchronize e o modelo do Puma com vários processos, cada um com várias threads. Nada disso se repete aqui. Este curso supõe que você sabe que threads existem, por que o Ruby as usa apesar do GVL e que o Mutex evita disputas. As sete aulas tratam do que acontece quando uma thread trava, de dois locks em deadlock e de checar a afirmação sobre I/O com um cronômetro em vez de um diagrama.

Uma thread tem um status que você pode inspecionar

t = Thread.new { sleep 0.3 }
sleep 0.05
t.status
# "sleep"
t.alive?
# true

t.join
t.status
# false
t.alive?
# false

Thread#status devolve uma String, e não um símbolo, enquanto a thread faz algo que o Ruby sabe nomear: "sleep" aqui, já que a thread está bloqueada no sleep. Uma thread fazendo trabalho comum informa "run". Quando uma thread termina normalmente, status devolve false em vez de uma string, e alive? também vira false.

Três finais, valores diferentes

Uma thread pode parar por três motivos, e o status os informa assim:

# Terminou normalmente
t1 = Thread.new { 1 + 1 }
t1.join
t1.status
# false

# Morreu por causa de uma exceção não tratada
t2 = Thread.new { raise "boom" }
sleep 0.1
t2.status
# nil

# Morta explicitamente
t3 = Thread.new { sleep 1 }
t3.kill
sleep 0.05
t3.status
# false

false quer dizer "terminou sem exceção". nil quer dizer "terminou por causa de uma exceção não tratada". Essa diferença permite ao código distinguir uma thread que concluiu o trabalho de uma que quebrou lendo o status, sem envolver toda thread em begin/rescue.

O kill parece um final normal

Thread#kill (com Thread#exit e Thread#terminate como apelidos) para uma thread de fora, e o status informa isso como um final normal: false, sem um valor separado de "morta". Se alguma lógica precisa distinguir "terminou sozinha" de "foi morta por outro código", ela precisa registrar isso à parte, porque o status sozinho não diz qual foi.

Por que isso importa no resto do curso

Toda aula seguinte, a demo de deadlock, os exemplos de fila e os benchmarks, precisa responder "esta thread ainda está fazendo algo, e se não, como parou?" sem chutar. status e alive? respondem isso de fora da thread. A demo de deadlock da próxima aula se apoia neles para mostrar que duas threads nunca terminaram, em vez de deduzir isso de um terminal travado.

Pontos-chave

  • Thread#status devolve uma string como "sleep" ou "run" enquanto a thread está ativa.
  • Uma thread que terminou normalmente ou levou .kill informa false; uma que morreu por exceção não tratada informa nil.
  • Thread#alive? é um booleano simples: true para uma thread que não parou.
  • O status sozinho não distingue "terminou sozinha" de "foi morta por outro código": os dois informam false.
Aula 1 de 7 · grátis

Continue com a aula 2

abort_on_exception e report_on_exception

Como report_on_exception registra a exceção não tratada de uma thread e abort_on_exception a levanta de novo na principal.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...