Thread#status e o ciclo de vida de uma thread
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#statusdevolve uma string como"sleep"ou"run"enquanto a thread está ativa.- Uma thread que terminou normalmente ou levou
.killinformafalse; uma que morreu por exceção não tratada informanil. Thread#alive?é um booleano simples:truepara uma thread que não parou.- O
statussozinho não distingue "terminou sozinha" de "foi morta por outro código": os dois informamfalse.
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.