Come funziona dormire un thread?


14

Quando dormi un thread, cosa sta realmente succedendo?

Vedo che dormire un thread "mette in pausa il thread corrente per un determinato periodo di tempo" . Ma come funziona?

Secondo Come funziona Thread.sleep () internamente e Come funziona davvero Thread.sleep? :

  • la durata del sonno sarà soggetta ad una granularità specifica del sistema
  • il sonno sta bloccando
  • il thread lascia la CPU e interrompe la sua esecuzione
  • il thread non consuma tempo della CPU durante la sospensione

Non riesco proprio a capire bene la meccanica interna e fondamentale di cosa significhi tutto questo.

Capisco che esiste qualcosa chiamato scheduler che è responsabile del passaggio tra i thread.

Le fonti sembrano indicare che ciò varia in base al sistema operativo (o all'hardware?) E alla maggior parte dei thread vengono dati 1ms - 60ms circa per eseguire alcune azioni prima che la CPU passi a un altro thread.

Ma quando un thread dorme (ad esempio, molti secondi), come riprende? Immagino che un timer sia coinvolto in qualche modo, è l'orologio della scheda madre? È correlato alla frequenza di clock della CPU?

E anche se è coinvolto un timer, come fa la CPU a sapere quando è il momento di prestare nuovamente attenzione al thread? Non dovrebbe controllare costantemente sul thread per vedere se è pronto? Non è che effettivamente polling e quindi tipo di sta consumando tempo di CPU?

Dormire è un thread specifico della lingua o è il sistema operativo responsabile o è una cosa specifica della CPU?

Qualcuno potrebbe spiegarmi questo con spiegazioni di base su cose come lo scheduler e cosa sta facendo la CPU durante tutto questo?


2
Il risveglio di un thread inattivo funziona nuovamente con interruzioni temporizzate, in genere generate da un clock di interruzione, che è un componente hardware separato dalla parte principale della CPU che elabora le istruzioni. Ciò evita le esigenze di polling. Forse questa spiegazione su Quora chiarirà alcune cose: quora.com/How-does-threading-work-at-CPU-level
Doc Brown,

1
La maggior parte delle JVM in realtà non implementano il multi-threading: tutto ciò che fanno è utilizzare le funzionalità multi-threading del sistema operativo sottostante. Se vuoi davvero sapere come funziona, ci sono molti libri sull'argomento della progettazione del sistema operativo.
Solomon Slow

Risposte:


11

Esiste molto di più nell'esecuzione di un programma oltre al semplice codice all'interno di quel programma.

Qualsiasi programma che viene eseguito in un sistema operativo multi-processo è sotto il controllo dello scheduler del sistema operativo e lo scheduler mantiene una tabella esplicita che dice quale processo è in esecuzione, quali sono in attesa di essere eseguiti quando sono disponibili cicli della CPU e quali non sono nemmeno cercando di correre (dormendo). Lo scheduler in genere assegna fasce orarie di dimensioni pari ai processi in base alla priorità e alla cronologia di esecuzione. In definitiva, questo loop è guidato da interrupt di processo, generalmente generati da un oscillatore sulla scheda principale.

La sospensione è sempre una funzionalità che un linguaggio di programmazione può supportare solo perché l'ambiente di runtime in cui verrà eseguito lo supporta. Un programma normale non può sospendere se stesso , si può dire solo lo scheduler come sarebbe piacerebbe essere trattati - e lo scheduler è in alcun modo obbligati o addirittura sempre in grado di soddisfare quel desiderio. Pensa a un laptop chiuso e in letargo; l'oscillatore della scheda principale continua a pulsare, ma poiché lo scheduler non è in esecuzione, nessun processo può essere eseguito, indipendentemente dalla sua priorità.


Questo è (generalmente) vero per i processi, ma non sempre per i thread, che a volte dipendono dalla lingua. I thread possono essere implementati indipendentemente dal sistema operativo e possono essere cooperativi o preventivi. Ad esempio, Ruby ha "fibre" (oltre ai fili). Le fibre di rubino sono programmate in modo cooperativo.
david25272,

È vero, solo i thread nativi funzionano in questo modo. I thread verdi sono programmati dalla VM che esegue un programma in una lingua compilata in byte. Di solito vengono utilizzati quando i thread nativi non sono disponibili o quando si esegue codice che non è propriamente thread-safe (la VM a volte può garantire che la semantica di un programma multi-thread rimanga corretta in modi che lo scheduler del sistema operativo non può).
Kilian Foth,

7

Come ha menzionato Doc Brown in un commento, gli interrupt sono la chiave e non solo per dormire.

Un interrupt è un segnale hardware che il processore dovrebbe interrompere ciò che sta facendo ed eseguire un pezzo di codice. I dispositivi esterni attivano gli interrupt quando richiedono l'attenzione del processore: ad esempio, quando un disco ha terminato la lettura dei dati, oppure è stato premuto un tasto o un timer per il conto alla rovescia sulla scheda madre ha raggiunto lo zero.

Il codice di gestione delle interruzioni è generalmente molto piccolo e molto veloce. Ad esempio, quando il disco indica che un blocco è stato copiato in memoria, il sistema operativo potrebbe semplicemente registrare quel fatto in un elenco di "blocchi pronti" da qualche parte e quindi tornare a qualsiasi altra cosa stesse facendo. Non si desidera che la CPU passi tutto il suo tempo nel codice di gestione degli interrupt e non esegua il codice utente.

Un pezzo di codice guidato dall'interruzione che non è necessariamente piccolo è lo scheduler. Viene attivato da un segnale proveniente da un conto alla rovescia ed esamina lo stato del sistema ogni volta che viene eseguito. Questo in genere include l'identificazione di processi pronti per l'esecuzione (ad esempio, perché il blocco che stavano aspettando è arrivato in memoria), così come quelli che hanno esaurito il loro intervallo di tempo.

Quindi, quando esegui un thread sleep, quello che stai facendo è dire al sistema operativo che (1) stai rinunciando alla tua fascia oraria e (2) non dovresti essere risvegliato di nuovo fino a quando non è trascorso un certo tempo.

Ogni volta che lo scheduler viene eseguito, esaminerà il tuo thread e lo contrassegnerà come "pronto per l'esecuzione" solo se è trascorso quel tempo. Questo è polling, in un certo senso, ma non è polling "busy-loop" poiché è innescato da un interrupt. Inoltre non è così costoso: in genere ci sono solo un migliaio di thread in esecuzione alla volta.

Questo dovrebbe anche darti un'idea del perché i tempi di sospensione non sono esatti: quando il tuo thread diventa pronto per essere eseguito, potrebbero esserci altri thread che sono ancora in esecuzione e non hanno esaurito il loro intervallo di tempo. Oppure potrebbero esserci thread con priorità più alta pronti per essere eseguiti.


Questo è il modo in cui funzionano i sistemi operativi "moderni". Nei sistemi operativi precedenti, come Windows 3 o Mac OS prima di OS X, un processo doveva produrre () controllo al sistema operativo. Sfortunatamente se un programma rimanesse bloccato in un loop o in qualche modo bloccato, potrebbe non cedere mai il controllo e l'intero sistema si bloccherebbe.
david25272,

@ david25272 - Penso che userei la parola "più semplice" piuttosto che "più vecchia", dato che c'erano sistemi degli anni '60 che utilizzavano il multitasking preventivo. E mentre è vero che il multtasking cooperativo richiede che il thread attivo faccia qualcosa per rilasciare il suo controllo del processore (in genere effettuando una chiamata di sistema bloccante, piuttosto che un rendimento esplicito), non credo che ci siano molti programmatori di uso generale oggi che usano un sistema operativo con un modello di threading cooperativo.
kdgregory,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.