I lettori come te aiutano a sostenere MUO. Quando effettui un acquisto utilizzando i link sul nostro sito, potremmo guadagnare una commissione di affiliazione. Per saperne di più.

Su Linux, puoi creare e gestire thread in C/C++ usando la libreria thread POSIX (pthread). A differenza di altri sistemi operativi, c'è poca differenza tra un thread e un processo in Linux. Ecco perché Linux fa spesso riferimento ai suoi thread come processi leggeri.

Utilizzando la libreria pthread, puoi creare thread, attendere che terminino e terminarli in modo esplicito.

La storia dell'utilizzo dei thread su Linux

Prima della versione 2.6 di Linux, l'implementazione del thread principale era LinuxThreads. Questa implementazione presentava limiti significativi in ​​termini di prestazioni e operazioni di sincronizzazione. Un limite al numero massimo di thread che potevano essere eseguiti li limitava a migliaia.

Nel 2003, un team guidato da sviluppatori di IBM e RedHat è riuscito a realizzare il Libreria di thread POSIX nativa

instagram viewer
(NPTL) progetto disponibile. È stato introdotto per la prima volta in RedHat Enterprise versione 3 per risolvere i problemi di prestazioni con la Java Virtual Machine su Linux. Oggi, la libreria GNU C contiene implementazioni di entrambi i meccanismi di threading.

Nessuno di questi è un'implementazione di thread verdi, che una macchina virtuale gestirà ed eseguirà in modalità puramente utente. Quando usi la libreria pthread, il kernel crea un thread ogni volta che si avvia un programma.

È possibile trovare informazioni specifiche sui thread per qualsiasi processo in esecuzione nei file sotto /proc//task. Questa è la posizione standard per le informazioni di processo sotto lo standard Linux procfs. Per le applicazioni a thread singolo, sembrerà che in questa directory sia presente un record di attività con lo stesso valore del PID.

Logica di lavoro dei thread

I thread sono come i processi attualmente in esecuzione sul sistema operativo. Nei sistemi a processore singolo (ad esempio microcontrollori), il kernel del sistema operativo simula i thread. Ciò consente l'esecuzione simultanea delle transazioni attraverso lo slicing.

Un sistema operativo single-core può eseguire solo un processo alla volta. Tuttavia, dentro sistemi multicore o multiprocessore, questi processi possono essere eseguiti contemporaneamente.

Creazione filo in C

Puoi usare il pthread_create funzione per creare un nuovo thread. IL pthread.h il file di intestazione include la sua definizione di firma insieme ad altre funzioni relative ai thread. I thread utilizzano lo stesso spazio degli indirizzi e descrittori di file del programma principale.

La libreria pthread include anche il supporto necessario per le operazioni mutex e condizionali richieste per le operazioni di sincronizzazione.

Quando utilizzi le funzioni della libreria pthread, devi assicurarti che il compilatore colleghi il file pthread library nel tuo eseguibile. Se necessario, puoi istruire il compilatore a collegarsi alla libreria usando il file -l opzione:

gcc -o test test_thread.c -lpthread

La funzione pthread_create ha la seguente firma:

intpthread_create(pthread_t *filo, costpthread_attr_t *attr, vuoto *(*start_routine)(vuoto *), vuoto *arg)

Restituisce 0 se la procedura va a buon fine. Se c'è un problema, restituisce un codice di errore diverso da zero. Nella firma della funzione sopra:

  • IL filo parametro è di tipo pthread_t. Il thread creato sarà sempre accessibile con questo riferimento.
  • IL attr Il parametro consente di specificare un comportamento personalizzato. È possibile utilizzare una serie di funzioni specifiche del thread a partire da pthread_attr_ per impostare questo valore. Le possibili personalizzazioni sono la politica di pianificazione, la dimensione dello stack e la politica di distacco.
  • start_routine specifica la funzione che verrà eseguita dal thread.
  • arg rappresenta una struttura dati generica passata alla funzione dal thread.

Ecco un'applicazione di esempio:

#includere
#includere
#includere
#includere

vuoto *lavoratore(vuoto *dati)
{
char *nome = (char*)dati;

per (int io = 0; io < 120; io++)
{
dormi(50000);
printf("Ciao dal thread name = %s\n", name);
}

printf("Thread %s terminato!\n", name);
ritornoNULLO;
}

intprincipale(vuoto)
{
pthread_t th1, th2;
pthread_create(&th1, NULLO, lavoratore, "X");
pthread_create(&th2, NULLO, lavoratore, "Y");
sonno(5);
printf("Uscita dal programma principale\n");
ritorno0;
}

Tipi di filo

Quando un thread ritorna dal file principale() funzione in un'applicazione, tutti i thread terminano e il sistema libera tutte le risorse utilizzate dal programma. Allo stesso modo, quando si esce da qualsiasi thread con un comando come an Uscita(), il tuo programma terminerà tutti i thread.

Con il pthread_join funzione, puoi invece aspettare che un thread termini. Il thread che utilizza questa funzione si bloccherà fino al termine del thread previsto. Le risorse che utilizzano dal sistema non vengono restituite nemmeno in casi come la terminazione di thread unibili, non pianificati dalla CPU o addirittura il mancato collegamento con ptread_join.

A volte ci sono situazioni in cui unirsi con pthread_join non ha senso; se è impossibile prevedere quando il thread finirà, per esempio. In questo caso, puoi assicurarti che il sistema restituisca automaticamente tutte le risorse nel punto in cui il thread ritorna.

Per raggiungere questo obiettivo, dovresti iniziare i thread pertinenti con il file DISTACCATO stato. Quando si avvia un thread, STACCARE lo stato può essere impostato tramite i valori degli attributi di un thread o con il pthread_detach funzione:

intpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
intpthread_detach(pthread_t filo);

Ecco un esempio di utilizzo di pthread_join(). Sostituisci la funzione main nel primo programma con la seguente:

intprincipale(vuoto)
{
pthread_t th1, th2;
pthread_create(&th1, NULLO, lavoratore, "X");
pthread_create(&th2, NULLO, lavoratore, "Y");
sonno(5);
printf("uscita dal programma principale\n");
pthread_join (th1, NULLO);
pthread_join (th2, NULLO);
ritorno0;
}

Quando compili ed esegui il programma, il tuo output sarà:

Ciao dal thread Y
Ciao dal thread X
Ciao dal thread Y
...
Ciao dal thread Y
uscendo dal programma principale
Ciao dal thread X
...
Ciao dal thread X
Thread X terminato!
Ciao dal thread Y
Discussione Y completata!

Terminazione del filo

Puoi cancellare un thread con una chiamata a pthread_cancel, passando il file corrispondente pthread_t id:

intpthread_cancel(pthread_t filo);

Puoi vederlo in azione nel codice seguente. Ancora una volta, solo il principale la funzione è diversa:

intprincipale(vuoto)
{
pthread_t th1, th2;
pthread_create(&th1, NULLO, lavoratore, "X");
pthread_create(&th2, NULLO, lavoratore, "Y");
sonno(1);
printf("> Annullamento discussione Y!!\n");
pthread_cancel (th2);
dormi(100000);
printf("> Annullamento thread X!\n");
pthread_cancel (th1);
printf("uscita dal programma principale\n");
ritorno0;
}

Perché vengono creati i thread?

I sistemi operativi tentano sempre di eseguire thread su una o più CPU, da un elenco creato dall'utente o da un elenco di thread creato dall'utente. Alcuni thread non possono essere eseguiti perché sono in attesa di un segnale di input/output dall'hardware. Potrebbero anche essere in attesa volontariamente, in attesa di una risposta da un altro thread o avere un altro thread che li blocca.

Puoi regolare le risorse che assegni ai thread che crei usando pthread. Questa può essere una politica di pianificazione personalizzata oppure puoi scegliere algoritmi di pianificazione come FIFO o Round-robin se lo desideri.