Funzione pThread_create in lingua C

Funzione pThread_create in lingua C

Concettualmente, un programma è un singolo thread che esegue diversi compiti seriali, uno dopo l'altro.
La lingua C ci consente di scrivere programmi multithread utilizzando la libreria PThread dello standard Posix.
Un programma multi-thread è un thread o un compito che funziona in parallelo e contemporaneamente al programma principale e ad altri thread aperti dallo stesso programma in una parte di esso.

In questo Suggerimento Linux Articolo, imparerai come creare un thread da un programma principale utilizzando il pThread_create () funzione della libreria PThread.

Questo spiega i meccanismi teorici di questa funzione, la sua sintassi, gli argomenti di input e output e il tipo di dati accettato in ciascun caso.
Applicheremo quindi ciò che abbiamo imparato in esempi pratici, inclusi frammenti e immagini di codice, in cui creiamo e sincronizziamo i thread dalla funzione principale.

Sintassi della funzione pThread_create () in lingua C

int pThread_create (pThread_t *limita thread,
const pthread_attr_t *limita attr,
void *( *start_routine) (void *),
void *limitare argom);

Descrizione della funzione pThread_create () in lingua C

IL pThread_create () La funzione crea un thread ed lo esegue, in parallelo e contemporaneamente al programma che l'ha creata. Questa funzione esegue la routine specificata dal suo puntatore nell'ingresso start_routine Passandolo l'argomento input arg.

Successivamente, esaminiamo gli argomenti di input e output di pThread_create () in dettaglio, così come una descrizione dell'opera che ciascuno di questi argomenti svolge all'interno della funzione.

filo: Questo è un argomento di output che restituisce l'identificatore del thread creato. Questo identificatore viene utilizzato per fare riferimento a alcune funzioni di gestione dei thread come pThread_join () o pThread_cancel ().

ATRT: Questa voce è il puntatore a una struttura di tipo pThread_attr_t i cui membri specificano gli attributi del nuovo thread. Quando questo argomento viene inviato a NULL, gli attributi del nuovo thread vengono presi con i loro parametri predefiniti.

start_routine: Questo è il puntatore della funzione che verrà eseguita dal nuovo thread.

arg: Questo è il puntatore dell'argomento secondo cui la funzione principale passa al nuovo thread.

Se il thread viene creato correttamente, pThread_create () restituisce 0 come risultato. Se si verifica un errore, restituisce -1 e si archivia nella variabile globale errno il valore numerico specifico che rappresenta tale errore.

IL pThread_create () La funzione è definita nella pThread.HEADER H. Per usarlo, le seguenti intestazioni devono essere incluse in ".File C ", come mostrato di seguito:

#includere
#includere

Errori di compilazione nei programmi con thread

Quando si compilano i programmi GCC che utilizzano i thread, la compilation potrebbe fallire se non eseguita correttamente dalla riga di comando.
Il messaggio di errore più comune emesso dal compilatore afferma che una delle funzioni del thread a cui ci riferiamo nel codice non è definita.

Questi errori spesso comportano perdere tempo prezioso a controllare le intestazioni che abbiamo inserito nel codice, nella loro integrità e nelle directory associate al compilatore, poiché tutto indica che il problema è lì.
Sebbene le funzioni che causano l'errore siano definite nella "Pthread.H ”” ”e incluso nel codice, il compilatore non riconosce queste funzioni a meno che la libreria PThread non venga chiamata dalla riga di comando durante la compilation.

Di seguito, puoi vedere in verde il modo corretto di chiamare la libreria PThread dalla console di comando durante la compilazione di programmi con thread:

~ $ GCC -PThread Path/FileName.c -o out_name

Come mostrato nella figura seguente, l'errore scompare quando viene chiamata la libreria PThread durante la compilazione.

Come creare ed eseguire un thread con la funzione pThread_create () nella lingua C

In questo esempio, spiegheremo come pThread_create () lavori. Per fare ciò, creeremo una funzione principale e da lì apriremo un thread che esegue il thread_function () funzione in parallelo con funzione principale.

Il codice per questo esempio è costituito da due sezioni, il principale() funzione e thread_function () funzione, che è il thread.
Successivamente, spiegheremo ciascuna delle due funzioni separatamente e poi le metteremo insieme per compilare ed eseguire il codice.

thread_function (): Questa funzione è composta da a per Loop con 5 cicli, in ciascuno dei quali il messaggio "dal thread" viene visualizzato nella console di comando e dopo un ritardo di 3 secondi il ciclo viene nuovamente ripetuto. Il messaggio di questa funzione è interlacciato con quello del principale() funzione in modo da poter vedere in tempo reale cosa sta facendo ciascuno dei processi contemporaneamente.

Successivamente, vediamo NCL il NCLUS thread_function () funzione e definizione del suo prototipo:

void* thread_function (void* n);
void* thread_function (void* n)

per (int a = 0; a!= 5; a ++)

printf ("dal thread \ n");
sonno (3);

printf ("thread nclus \ n");
pThread_exit (n);

funzione principale: In questo esempio, il principale() La funzione è Nclusióne per definire le variabili e creare il thread.

Il primo passo nella creazione di un thread è definire una variabile di tipo pThread_t che NCL funge da identificatore del thread. In questo esempio, NCL chiamiamo questa variabile Thread_1.

Per NCLUS il thread, chiamiamo il pThread_create () Funzionare e passare il thread dell'identificatore thread_1 come primo argomento.
Gli attributi del thread da creare sono preimpostati in questo caso, quindi il secondo argomento di input è nullo.
Come terzo argomento, passiamo il puntatore alla funzione da eseguire nel nuovo thread, in questo caso thread_function ().
Dal momento che non abbiamo bisogno di trasmettere argomenti al nuovo thread in questo esempio, anche il puntatore arg NCL deve essere nullo.

Dopo aver chiamato pThread_create (), Il nuovo thread inizia l'esecuzione e la funzione principale() entra a per Loop di 5 cicli, ognuno dei quali stampa il messaggio "dalla funzione principale" nidificata con il messaggio "dal thread" della funzione thread_function (). Dopo ogni messaggio, un ritardo di 3 secondi viene inserito nei loop per entrambe le funzioni prima dell'inizio di un nuovo ciclo.

Di seguito è possibile vedere la funzione NcLUS principale(), il Nclusión delle intestazioni necessarie e la dichiarazione del prototipo della funzione thread_function ():

#includere
#includere
#includere
#includere
void* thread_function (void* dati);
int main ()

pThread_t thread_1;
printf ("Creazione del thread ... \ n");
pThread_create (& thread_1, null, thread_function, null);
per (int a = 0; a!= 5; A ++)

printf ("dalla funzione principale \ n");
sonno (3);

sonno (3);
restituzione 0;

Successivamente, vediamo il codice completo per questo esempio. Copia e incolla questo frammento in un file con ".C ”estensione. Compilare il codice ed eseguirlo per vedere come il principale() funzione e il nuovo thread eseguono le loro attività contemporaneamente.

#includere
#includere
#includere
#includere
void* thread_function (void* dati);
int main ()

pThread_t thread_1;
printf ("Creazione del thread ... \ n");
pThread_create (& thread_1, null, thread_function, null);
per (int a = 0; a!= 5; A ++)

printf ("dalla funzione principale \ n");
sonno (3);

restituzione 0;

/*********************************************** ****************/
void* thread_function (void* n)

per (int a = 0; a!= 5; a ++)

printf ("dal thread \ n");
sonno (3);

printf ("fine del thread \ n");
pThread_exit (N);

L'immagine che vediamo di seguito mostra l'attività eseguita dal thread che abbiamo creato con il pThread_create () funzione in parallelo con il compito del principale() funzione e i messaggi che ciascuno di essi invia alla console di comando:

Sincronizzazione dei thread nella lingua C

Nel codice dell'esempio precedente, il tempo di esecuzione del thread è più breve di quello del principale() funzione e quindi entrambi fanno il proprio lavoro correttamente. Ciò è dovuto al ritardo di 3 secondi che si verifica quando il principale() La funzione esce dal ciclo.
Tuttavia, se i tempi di esecuzione di un thread sono più lunghi di quelli del principale() funzione ed è completamente eseguita, il programma termina e tutti i thread che sono stati creati e stanno ancora eseguendo un'attività sono automaticamente chiusi.

Vediamo cosa succede nel codice dell'esempio precedente se impostiamo un ritardo di 1 secondo per ciclo nel ciclo per principale() funzione e uno di 3 secondi nel ciclo del thread.

Come mostrato nella foto, il principale() la funzione ha completato i 5 cicli del suo per Loop, mentre il thread poteva eseguire solo 3 cicli prima della chiusura del programma.

La chiusura di un thread senza eseguire completamente può portare a problemi critici in alcuni casi, in quanto potrebbe conservare i dati generati dall'utente, scrivere su un file system o un dispositivo di archiviazione o eseguire qualche altra attività al momento della risoluzione.
Per evitare questi problemi, è importante sviluppare un meccanismo per "attendere" il thread completare l'esecuzione prima di chiudere il programma o eseguire un'attività. IL pThread_Join () La funzione interrompe la funzione che ha creato il thread fino a quando quel thread non termina la sua esecuzione.

IL pThread_Join () La funzione prende due argomenti di input. Il primo è l'identificatore del thread restituito dal pThread_create () funzione quando viene creato il thread e il secondo argomento è il puntatore a una variabile che restituisce lo stato di uscita del thread.

Successivamente, utilizziamo il codice dall'esempio precedente, ma sostituiamo il per Loop of the principale() funzione con il pThread_Join () funzione, come mostrato di seguito:

#includere
#includere
#includere
#includere
void* thread_function (void* dati);
int main ()

pThread_t thread_1;
printf ("Creazione del thread ... \ n");
pThread_create (& thread_1, null, thread_function, null);
pThread_Join (thread_1, null);
restituzione 0;

/*********************************************** ****************/
void* thread_function (void* n)

per (int a = 0; a!= 5; a ++)

printf ("dal thread \ n");
sonno (3);

printf ("fine del thread \ n");
pThread_exit (n);

In questo caso, il principale() La funzione creerà solo il thread e attende che finisca la sua attività, quindi chiuderà il programma.

Possibili errori che la funzione pThread_create () può generare e come riconoscerli

IL pThread_create () La funzione può generare vari errori, dalle impostazioni degli attributi non validi alle risorse di sistema insufficienti per il nuovo thread.
Quando una funzione genera un errore, un codice di identificazione dell'errore numerico viene archiviato nella variabile globale errno. Questa variabile e le definizioni numeriche per ciascun errore sono definite in "Errno.H ”intestazione.
Di seguito è riportata una descrizione di ciascun errore che può verificarsi quando si chiama il pThread_create () funzione e la sua rappresentazione numerica definita in "errno.H".

Eagain: Non ci sono risorse disponibili per creare un altro thread. La rappresentazione numerica di questo errore è 35.

Einval: La configurazione degli attributi in ATRT non è valida. La rappresentazione numerica di questo errore è 22.

Eperm: Operazione non consentita. Questo errore si verifica quando non si dispone di autorizzazioni sufficienti per impostare i parametri dell'attributo in ATRT. La rappresentazione numerica di questo errore è 1.

Conclusione

In questo Suggerimento Linux Articolo, ti abbiamo mostrato come usare il pThread_create () Funzione per creare programmi multitasking con thread che sono in parallelo con la funzione principale.

Ti abbiamo anche detto come compilare programmi che usano i thread correttamente dalla riga di comando.
Abbiamo anche incluso una sezione speciale che spiega l'importanza di tenere conto dei tempi di esecuzione dei thread creati e ti abbiamo insegnato come sincronizzare i thread con la funzione principale per ottenere la corretta esecuzione.