Non riesco ad aggiungere direttamente alle risposte eccellenti fornite da David, templatetypedef ecc. - se si desidera evitare la latenza delle comunicazioni tra thread e lo spreco di risorse, non eseguire le comunicazioni tra thread con i cicli sleep().
preventiva programmazione/dispacciamento:
A livello di CPU, interrupt sono la chiave. Il sistema operativo non fa nulla fino a quando si verifica un'interruzione che causa l'inserimento del suo codice. Si noti che, in termini di sistema operativo, gli interrupt sono disponibili in due versioni: interruzioni hardware "reali" che causano l'esecuzione dei driver e "interrupt software", chiamate di sistemi operativi da thread già in esecuzione che possono potenzialmente causare il set di thread in esecuzione cambiare. Tasti, movimenti del mouse, schede di rete, dischi, errori di pagina generano interruzioni hardware. Le funzioni wait e signal e sleep() appartengono a quella seconda categoria. Quando un interrupt hardware provoca l'esecuzione di un driver, il driver esegue qualsiasi gestione hardware che è stata progettata per eseguire. Se il driver deve segnalare al sistema operativo che alcuni thread devono essere eseguiti, (forse un buffer del disco è ora pieno e deve essere elaborato), il sistema operativo fornisce un meccanismo di ingresso che il guidatore può chiamare invece di eseguire direttamente un interrupt- restituire se stesso, (importante!).
Gli interrupt come gli esempi precedenti possono rendere i thread che erano in attesa pronti per l'esecuzione e/o possono far entrare un thread in esecuzione in uno stato di attesa. Dopo aver elaborato il codice dell'interrupt, il sistema operativo applica i suoi algoritmi di pianificazione per decidere se il set di thread in esecuzione prima dell'interrupt è lo stesso del set che dovrebbe essere ora eseguito. Se lo sono, il sistema operativo solo interrompe: restituisce, in caso contrario, il sistema operativo deve anticipare uno o più thread in esecuzione. Se il sistema operativo deve anticipare un thread in esecuzione su un core della CPU che non è quello che ha gestito l'interrupt, deve ottenere il controllo di quel core della CPU. Lo fa per mezzo di un interrupt hardware "reale": il driver del processore del sistema operativo imposta un segnale hardware che interrompe il core che esegue il thread che deve essere interrotto.
Quando un thread che deve essere inserito entra nel codice del sistema operativo, il sistema operativo può salvare un contesto completo per il thread.Alcuni dei registri saranno già stati salvati nello stack del thread tramite la voce di interrupt e quindi il salvataggio dello stack-pointer del thread consentirà di "salvare" tutti quei registri, ma normalmente il sistema operativo dovrà fare di più, per esempio. potrebbe essere necessario svuotare le cache, potrebbe essere necessario salvare lo stato della FPU e, nel caso in cui il nuovo thread da eseguire appartenga a un processo diverso da quello da preempire, i registri di protezione della gestione della memoria dovranno essere sostituiti . Di solito, il sistema operativo passa dallo stack di thread interrotto a uno stack di sistemi operativi privati il prima possibile per evitare di imporre requisiti di stack di sistema operativo su ogni stack di thread.
Una volta che il/i contesto/i è/sono stati salvati, il SO può "scambiare" il/i contesto/i esteso/i per il/i nuovo/i thread/i da rendere in esecuzione. Ora il sistema operativo può finalmente caricare lo stack-pointer per il nuovo/i thread/i ed eseguire interrupt-return per far funzionare i nuovi thread pronti.
Il sistema operativo quindi non fa nulla. I thread in esecuzione funzionano finché non si verifica un altro interrupt, (hard o soft).
punti importanti:
1) Il kernel del sistema operativo dovrebbe essere guardato come un grande interrupt-handler che può decidere di interrompere ritorno a un diverso insieme di fili di quelli interrotti.
2) Il sistema operativo può ottenere il controllo e interrompere, se necessario, qualsiasi thread in qualsiasi processo, indipendentemente dallo stato in cui si trova o dal centro su cui può essere eseguito.
3) La pianificazione e l'invio preventivi generano tutti i problemi di sincronizzazione, ecc. Che sono pubblicati su questi forum. Il grande vantaggio è la rapida risposta a livello di thread a interruzioni hard. Senza questo, tutte quelle app ad alte prestazioni che si eseguono sul PC - streaming video, reti veloci ecc. Sarebbero praticamente impossibili.
4) Il timer del sistema operativo è solo una delle numerose interruzioni che possono modificare il set di thread in esecuzione. 'Time-slicing', (ugh - odio quel termine), tra thread pronti si verifica solo quando il computer è sovraccarico, vale a dire. l'insieme di thread pronti è maggiore del numero di core CPU disponibili per eseguirli. Se un testo che pretende di spiegare la pianificazione del sistema operativo menziona "time-slicing" prima di "interrupts", è probabile che causi più confusione che spiegazione. L'interruzione del timer è solo "speciale" in quanto molte chiamate di sistema hanno timeout per il backup della loro funzione principale, (OK, per sleep(), il timeout È la funzione primaria :).
Basta chiedersi, non è così che le funzioni di attesa funzionano internamente comunque? (Esclusa ovviamente l'eccezione.) – Mehrdad
@ Mehrdad- In genere no. Di solito i thread sono collocati in una "coda di attesa" e non viene fornito alcun tempo di processore. Quando si verificano alcuni eventi che li riattivano, vengono reinseriti nella coda di esecuzione in modo che vengano pianificati. Ciò significa che potresti avere un milione di thread dormienti senza alcuna perdita di prestazioni se solo due o tre thread sono attivi in qualsiasi momento. – templatetypedef
@templatetypedef: Quindi in che modo esattamente il sistema operativo determina se i thread devono essere risvegliati in una particolare fascia oraria? Non dovrebbe controllare lo stato del thread in un loop ad ogni fettina? – Mehrdad