Como dormir um thread funciona?

14

Quando você dorme um fio, o que realmente está acontecendo?

Vejo que dormir um encadeamento "pausa o encadeamento atual por um determinado período de tempo" . Mas como isso funciona?

De acordo com Como Thread.sleep () funciona internamente e como o Thread.sleep realmente funciona? :

  • a duração do sono estará sujeita a alguma granularidade específica do sistema
  • o sono está bloqueando
  • o thread sai da CPU e interrompe sua execução
  • o encadeamento não está consumindo tempo de CPU enquanto dorme

Simplesmente não consigo entender bem a mecânica interna e fundamental do que tudo isso significa.

Entendo que existe algo chamado agendador responsável pela alternância entre threads.

As fontes parecem indicar que isso varia de acordo com o sistema operacional (ou hardware?) E a maioria dos threads recebe de 1 a 60 ms para executar algumas ações antes que a CPU mude para outro thread.

Mas quando um thread dorme (por exemplo, muitos segundos), como ele é retomado? Acho que um temporizador está envolvido de alguma forma, é o relógio da placa-mãe? Está relacionado à taxa de clock da CPU?

E mesmo que um temporizador esteja envolvido, como a CPU sabe quando é hora de prestar atenção ao encadeamento novamente? Não seria necessário verificar constantemente o tópico para ver se está pronto? Isso não está efetivamente pesquisando e, portanto, está consumindo tempo de CPU?

O modo de suspensão é específico do idioma do encadeamento ou o SO é responsável por isso ou é específico da CPU?

Alguém poderia me explicar isso com explicações básicas de coisas como o agendador e o que a CPU está fazendo durante tudo isso?

Rowan Freeman
fonte
2
Despertar um encadeamento adormecido novamente funciona por interrupções cronometradas, normalmente geradas por um relógio de interrupção, que é um componente de hardware separado da parte principal da CPU que processa as instruções. Isso evita as necessidades de votação. Talvez essa explicação sobre Quora irá esclarecer algumas coisas: quora.com/How-does-threading-work-at-CPU-level
Doc Brown
11
A maioria das JVMs na verdade não implementa multiencadeamento: tudo o que eles fazem é usar os recursos de multiencadeamento do sistema operacional subjacente. Se você realmente quer saber como isso funciona, existem muitos livros sobre o design do sistema operacional.
Solomon Slow

Respostas:

11

Há muito mais envolvido na execução de um programa do que apenas o código dentro desse programa.

Qualquer programa que é executado em um sistema operacional com vários processos está sob o controle do agendador do sistema operacional , e o agendador mantém uma tabela explícita dizendo qual processo está em execução, quais estão aguardando para serem executados quando os ciclos da CPU estão disponíveis e quais nem são tentando correr (dormindo). O agendador normalmente atribui fatias de tamanho uniforme aos processos, dependendo de sua prioridade e histórico de execução. Por fim, esse loop é causado por interrupções de hardware, geralmente geradas por um oscilador na placa principal.

Dormir é sempre um recurso que uma linguagem de programação pode suportar apenas porque o ambiente de tempo de execução em que será executado o suporta. Um programa normal não pode suspender -se , ele só pode dizer o programador como ele iria gostar de ser tratado - e o programador não é de forma obrigado ou mesmo sempre capazes de satisfazer esse desejo. Pense em um laptop sendo fechado e entrando em hibernação; o oscilador da placa principal continua pulsando, mas, como o agendador não está em execução, nenhum processo pode estar em execução, independentemente da sua prioridade.

Kilian Foth
fonte
Isso é (geralmente) verdadeiro para processos, mas nem sempre é verdade para threads, que às vezes dependem da linguagem. Os encadeamentos podem ser implementados independentemente do sistema operacional e podem ser cooperativos ou preventivos. Por exemplo, Ruby tem "fibras" (além de threads). As fibras de rubi são agendadas cooperativamente.
precisa saber é o seguinte
É verdade que apenas os threads nativos funcionam assim. Threads verdes são agendados pela VM executando um programa em um idioma compilado por bytes. Geralmente, eles são usados ​​quando os threads nativos não estão disponíveis ou ao executar o código que não é adequadamente seguro para threads (a VM às vezes pode garantir que a semântica de um programa com vários threads permaneça correta de maneiras que o agendador do SO não pode).
precisa saber é o seguinte
7

Como Doc Brown mencionou em um comentário, interrupções são a chave, e não apenas para dormir.

Uma interrupção é um sinal de hardware de que o processador deve parar o que está fazendo e executar um pedaço de código. Dispositivos externos acionam interrupções quando precisam da atenção do processador: por exemplo, quando um disco termina de ler os dados, pressiona uma tecla ou um contador regressivo na placa-mãe atinge zero.

O código de manipulação de interrupção geralmente é muito pequeno e muito rápido. Por exemplo, quando o disco indica que um bloco foi copiado na memória, o sistema operacional pode simplesmente registrar esse fato em uma lista de "blocos prontos" em algum lugar e depois retornar ao que quer que esteja fazendo. Você não quer que a CPU gaste todo o seu tempo no código de manipulação de interrupções e não executando o código do usuário.

Um pedaço de código acionado por interrupção que não é necessariamente pequeno é o agendador. É acionado por um sinal de um temporizador de contagem regressiva e examina o estado do sistema sempre que é executado. Isso normalmente inclui a identificação de processos que estão prontos para execução (por exemplo, porque o bloco que eles estavam esperando chegou na memória), bem como aqueles que esgotaram seu intervalo de tempo.

Portanto, quando você executa uma suspensão do encadeamento, o que está fazendo é dizer ao sistema operacional que (1) você está desistindo da sua fatia de tempo e (2) não deve ser acordado novamente até que um certo tempo tenha decorrido.

Sempre que o agendador for executado, ele analisará seu encadeamento e o marcará como "pronto para executar" se esse tempo tiver decorrido. Essa é uma pesquisa, de um tipo, mas não é uma pesquisa de "ciclo ocupado", pois é acionada por uma interrupção. Também não é tão caro: normalmente existem apenas cerca de mil threads em execução por vez.

Isso também deve lhe dar uma idéia de por que os tempos de suspensão não são exatos: quando o encadeamento ficar pronto para execução, poderá haver outros encadeamentos que ainda estejam em execução e que não tenham esgotado sua fatia de tempo. Ou pode haver threads de prioridade mais alta prontos para execução.

kdgregory
fonte
É assim que os sistemas operacionais "modernos" funcionam. Em sistemas operacionais mais antigos, como o Windows 3 ou o Mac OS anterior ao OS X, um processo precisava render () o controle do sistema operacional. Infelizmente, se um programa travasse em um loop ou travasse de alguma forma, ele nunca renderia controle e todo o sistema seria interrompido.
David25272
@ david25272 - Eu acho que usaria a palavra "mais simples" em vez de "mais antiga", pois havia sistemas da década de 1960 que faziam multitarefa preventiva. E embora seja verdade que a multitarefa cooperativa exija que o encadeamento ativo faça algo para liberar seu controle do processador (normalmente fazendo uma chamada de sistema de bloqueio, em vez de um rendimento explícito), não acredito que haja muitos programadores de uso geral hoje que usam um SO com um modelo de encadeamento cooperativo.
Kdgregory