GNU/Linux >> Linux Esercitazione >  >> Linux

Introduzione ai thread di Linux – Parte I

Un thread di esecuzione è spesso considerato come la più piccola unità di elaborazione su cui lavora uno scheduler.

Un processo può avere più thread di esecuzione che vengono eseguiti in modo asincrono.

Questa esecuzione asincrona introduce la capacità di ogni thread di gestire un particolare lavoro o servizio in modo indipendente. Quindi più thread in esecuzione in un processo gestiscono i loro servizi, che nel complesso costituiscono la capacità completa del processo.

In questo articolo toccheremo le basi dei thread e costruiremo la comprensione di base richiesta per apprendere la pratica aspetti dei thread di Linux.

Linux Threads Series:parte 1 (questo articolo), parte 2, parte 3.

Perché i thread sono necessari?

Ora, ci si potrebbe chiedere perché abbiamo bisogno di più thread in un processo? Perché un processo con un solo thread principale (predefinito) non può essere utilizzato in ogni situazione.

Bene, per rispondere a questo, consideriamo un esempio:

Supponiamo che ci sia un processo, che riceve input in tempo reale e corrisponda a ciascun input che deve produrre un determinato output. Ora, se il processo non è multi-thread, cioè se il processo non coinvolge più thread, l'intera elaborazione nel processo diventa sincrona. Ciò significa che il processo prende un input lo elabora e produce un output.

La limitazione nel progetto di cui sopra è che il processo non può accettare un input fino a quando non ha terminato l'elaborazione del precedente e nel caso in cui l'elaborazione di un input richieda più tempo del previsto, l'accettazione di ulteriori input viene sospesa.

Per considerare l'impatto della limitazione di cui sopra, se mappiamo l'esempio generico sopra con un processo server socket in grado di accettare connessioni di input, elaborarle e fornire output al client socket. Ora, se durante l'elaborazione di qualsiasi input se il processo del server richiede più tempo del previsto e nel frattempo un altro input (richiesta di connessione) arriva al server socket, il processo del server non sarebbe in grado di accettare la nuova connessione di input poiché è già bloccato elaborazione della vecchia connessione di ingresso. Ciò potrebbe causare un timeout di connessione al client socket che non è affatto desiderato.

Ciò dimostra che il modello di esecuzione sincrono non può essere applicato ovunque e quindi era sentito il requisito del modello di esecuzione asincrono implementato utilizzando i thread.

Differenza tra thread e processi

Di seguito sono riportate alcune delle principali differenze tra il thread e i processi:

  • I processi non condividono lo spazio degli indirizzi mentre i thread in esecuzione nello stesso processo condividono lo spazio degli indirizzi.
  • Da quanto sopra è chiaro che i processi vengono eseguiti indipendentemente l'uno dall'altro e la sincronizzazione tra i processi è curata solo dal kernel mentre d'altra parte la sincronizzazione dei thread deve essere curata dal processo in cui i thread sono in esecuzione
  • Il cambio di contesto tra i thread è veloce rispetto al cambio di contesto tra i processi
  • L'interazione tra due processi si ottiene solo attraverso la comunicazione tra processi standard, mentre i thread in esecuzione nello stesso processo possono comunicare facilmente poiché condividono la maggior parte delle risorse come memoria, segmento di testo ecc.

Thread utente vs thread del kernel

I thread possono esistere nello spazio utente così come nello spazio del kernel.

Uno spazio utente i thread vengono creati, controllati e distrutti utilizzando le librerie di thread dello spazio utente. Questi thread non sono noti al kernel e quindi il kernel non è coinvolto nella loro elaborazione. Questi thread seguono il multitasking cooperativo in cui un thread rilascia la CPU di propria volontà, ovvero lo scheduler non può anticipare il thread. I vantaggi dei thread dello spazio utente sono che il passaggio tra due thread non comporta molto sovraccarico ed è generalmente molto veloce mentre è negativo poiché questi thread seguono il multitasking cooperativo, quindi se un thread viene bloccato l'intero processo viene bloccato.

Uno spazio del kernel il thread viene creato, controllato e distrutto dal kernel. Per ogni thread che esiste nello spazio utente c'è un thread del kernel corrispondente. Poiché questi thread sono gestiti dal kernel, seguono il multitasking preventivo in cui lo scheduler può anticipare un thread in esecuzione con un thread a priorità più alta che è pronto per l'esecuzione. Il principale vantaggio dei thread del kernel è che anche se uno dei thread viene bloccato, l'intero processo non viene bloccato poiché i thread del kernel seguono la pianificazione preventiva mentre, sul lato negativo, il cambio di contesto non è molto veloce rispetto ai thread dello spazio utente.

Se parliamo di Linux, i thread del kernel sono ottimizzati a tal punto da essere considerati migliori dei thread dello spazio utente e utilizzati principalmente in tutti gli scenari tranne quando il requisito principale è quello del multitasking cooperativo.

Problemi con i thread

Ci sono alcuni problemi importanti che sorgono durante l'utilizzo dei thread :

  • Molti sistemi operativi non implementano i thread come processi, piuttosto vedono i thread come parte del processo padre. In questo caso, cosa accadrebbe se un thread chiama fork() o, peggio ancora, se un thread esegue un nuovo binario?? Questi scenari possono avere conseguenze pericolose, ad esempio nel problema successivo l'intero processo padre potrebbe essere sostituito con lo spazio degli indirizzi del binario appena eseguito. Questo non è affatto desiderato. Linux, che è un reclamo POSIX, si assicura che la chiamata a fork() duplichi solo il thread che ha chiamato la funzione fork() mentre un exec da qualsiasi thread arresterebbe tutti i thread nel processo padre.
  • Un altro problema che può sorgere sono i problemi di concorrenza. Poiché i thread condividono tutti i segmenti (tranne il segmento dello stack) e possono essere anticipati in qualsiasi fase dallo scheduler rispetto a qualsiasi variabile globale o struttura di dati che può essere lasciata in uno stato incoerente dalla prelazione di un thread potrebbe causare seri problemi quando il successivo ad alta priorità thread esegue la stessa funzione e utilizza le stesse variabili o strutture dati.

Per il problema 1 sopra menzionato, tutto ciò che possiamo dire è che si tratta di un problema di progettazione e la progettazione per le applicazioni dovrebbe essere eseguita in modo tale che sorgano meno problemi di questo tipo.

Per il problema 2 sopra menzionato, utilizzando i meccanismi di blocco il programmatore può bloccare un blocco di codice all'interno di una funzione in modo che anche se si verifica un cambio di contesto (quando la variabile globale della funzione e le strutture dati erano in uno stato incoerente), anche il thread successivo non è in grado di eseguire lo stesso codice fino a quando il blocco di codice bloccato all'interno della funzione non viene sbloccato dal thread precedente (o dal thread che lo ha acquisito).


Linux
  1. Nozioni di base sui segnali di Linux – Parte I

  2. Introduzione ai fondamenti del routing IP di Linux (Parte 1)

  3. Numero massimo di thread per processo in Linux?

  4. Stati del processo Linux

  5. I thread del kernel di Linux sono davvero processi del kernel?

Esempi di comandi curl Linux – Parte 2

Come uccidere un processo in Linux

Comando Pstree in Linux

Kill Command in Linux

Un'introduzione a Vivaldi Browser su Linux

Monitoraggio dei processi su Linux