Funkcja pthread_create w języku c

Funkcja pthread_create w języku c

Koncepcyjnie program to pojedynczy wątek, który wykonuje kilka zadań szeregowych, jeden po drugim.
Język C pozwala nam pisać programy wielowątkowe za pomocą biblioteki PTHREAD w standardu POSIX.
Program wielodokładny to wątek lub zadanie, które działa równolegle i jednocześnie z głównym programem i innymi wątkami otwartymi przez ten sam program w niektórych jego części.

W tym Wskazówka Linux Artykuł, dowiesz się, jak utworzyć wątek z głównego programu za pomocą pthread_create () Funkcja biblioteki pthread.

To wyjaśnia teoretyczne funkcjonowanie tej funkcji, jej składni, argumenty wejściowe i wyjściowe oraz typ danych zaakceptowany w każdym przypadku.
Następnie zastosujemy to, czego nauczyliśmy się w praktycznych przykładach, w tym fragmenty kodu i obrazów, w których tworzymy i synchronizujemy wątki z głównej funkcji.

Składnia funkcji pthread_create () w języku c

int pthread_create (pthread_t *ograniczyć wątek,
const pthread_attr_t *ogranicz attr,
void *( *start_routine) (void *),
void *ogranicz arg);

Opis funkcji pthread_create () w języku C

pthread_create () Funkcja tworzy wątek i wykonuje go równolegle i jednocześnie z programem, który go utworzył. Ta funkcja wykonuje procedurę określoną przez jej wskaźnik w wejściu start_routine Przekazując go argument wejściowy arg.

Następnie spójrzmy na argumenty wejściowe i wyjściowe pthread_create () szczegółowo, a także opis pracy każdy z tych argumentów wykonuje w ramach funkcji.

nitka: Jest to argument wyjściowy, który zwraca identyfikator utworzonego wątku. Ten identyfikator służy do odwoływania się do niego w niektórych funkcjach zarządzania wątkami, takimi jak pthread_join () lub pthread_cancel ().

attr: Ten wpis jest wskaźnikiem do struktury typu pthread_attr_t, którego członkowie określają atrybuty nowego wątku. Gdy ten argument zostanie wysłany do NULL, atrybuty nowego wątku są pobierane za pomocą ich domyślnych parametrów.

start_routine: To jest wskaźnik do funkcji, która zostanie wykonana przez nowy wątek.

arg: To jest wskaźnik do argumentu, że główna funkcja przechodzi do nowego wątku.

Jeśli wątek jest utworzony pomyślnie, pthread_create () zwraca 0 w wyniku. Jeśli wystąpi błąd, zwraca -1 i przechowuje w zmiennej globalnej errno konkretna wartość liczbowa reprezentująca ten błąd.

pthread_create () Funkcja jest zdefiniowana w PTHREAD.H Nagłówek. Aby go użyć, następujące nagłówki muszą być zawarte w „.plik C ”, jak pokazano poniżej:

#włączać
#włączać

Błędy kompilacji w programach z wątkami

Podczas kompilacji programów GCC, które używają wątków, kompilacja może się nie powieść, jeśli nie zostanie wykonana poprawnie z wiersza poleceń.
Najczęstszy komunikat o błędzie wydany przez kompilator stwierdza, że ​​jedna z funkcji wątku, które odwołujemy się w kodzie.

Błędy te często powodują marnowanie cennego czasu sprawdzania nagłówków, które wprowadziliśmy do kodu, ich integralności i katalogów związanych z kompilatorem, ponieważ wszystko wskazuje, że problem jest tam.
Chociaż funkcje, które powodują błąd, są zdefiniowane w „PTHREAD.H ”nagłówka i zawarty w kodzie, kompilator nie rozpoznaje tych funkcji, chyba że biblioteka PTHREAD jest wywoływana z wiersza poleceń podczas kompilacji.

Poniżej możesz zobaczyć na zielono poprawny sposób wywołania biblioteki PTHREAD z konsoli poleceń podczas kompilacji programów z wątkami:

~ $ gcc -pthread ścieżka/nazwa pliku.C -O out_name

Jak pokazano na poniższym rysunku, błąd znika, gdy biblioteka pthread jest wywoływana podczas kompilacji.

Jak utworzyć i wykonać wątek za pomocą funkcji pthread_create () w języku C

W tym przykładzie wyjaśnimy, jak pthread_create () Pracuje. Aby to zrobić, utworzymy główną funkcję i stamtąd otworzymy wątek, który wykonuje Thread_function () funkcja równolegle z główna funkcja.

Kod tego przykładu składa się z dwóch sekcji, główny() funkcja i Thread_function () funkcja, która jest wątkiem.
Następnie wyjaśnimy każdą z dwóch funkcji osobno, a następnie złożymy je, aby skompilować i uruchomić kod.

Thread_function (): Ta funkcja składa się z Do pętla z 5 cykli, w każdym z których wiadomość „z wątku” jest wyświetlana w konsoli dowodzenia, a po opóźnieniu 3 sekund cykl jest powtarzany ponownie. Przesłanie tej funkcji jest przeplatane z przesłaniem główny() funkcja, abyś mógł zobaczyć w czasie rzeczywistym, co każdy z procesów robi jednocześnie.

Następnie widzimy NCLUSI Thread_function () Funkcja i definicja jego prototypu:

void* Thread_Function (void* n);
void* Thread_function (void* n)

for (int a = 0; a!= 5; A ++)

printf („z wątku \ n”);
sen (3);

printf („nclus wątek \ n”);
pthread_exit (n);

główna funkcja: W tym przykładzie główny() Funkcja to nclusióne do definiowania zmiennych i tworzenia wątku.

Pierwszym krokiem w tworzeniu wątku jest zdefiniowanie zmiennej typu pthread_t że NCL służy jako identyfikator wątku. W tym przykładzie NCL nazywamy tę zmienną Thread_1.

Aby nclus wątek, nazywamy pthread_create () funkcjonuj i przekazuj wątek wątku wątku_1 jako pierwszy argument.
Atrybuty wątku do utworzenia są ustawione w tym przypadku, więc drugi argument wejściowy jest zerowy.
Jako trzeci argument przekazujemy wskaźnik do funkcji, która ma zostać wykonana w nowym wątku, w tym przypadku Thread_function ().
Ponieważ w tym przykładzie nie musimy przekazywać żadnych argumentów do nowego wątku, wskaźnik arg.

Po zadzwonieniu pthread_create (), Nowy wątek rozpoczyna wykonywanie i funkcję główny() wchodzi do Do pętla 5 cykli, z których każdy drukuje wiadomość „z funkcji głównej” zagnieżdżona komunikatem „z wątku” funkcji Thread_function (). Po każdym przesłaniu wkłada się opóźnienie 3 sekund do pętli dla obu funkcji przed rozpoczęciem nowego cyklu.

Poniżej możesz zobaczyć funkcję NCLUSI główny(), nclusión niezbędnych nagłówków i deklaracja prototypu funkcji Thread_Function ():

#włączać
#włączać
#włączać
#włączać
void* Thread_Function (void* dane);
int main ()

pThread_T Thread_1;
printf („Tworzenie wątku… \ n”);
pthread_create (& Thread_1, NULL, Thread_Function, NULL);
for (int a = 0; a!= 5; A ++)

printf („z funkcji głównej \ n”);
sen (3);

sen (3);
powrót 0;

Następnie widzimy pełny kod tego przykładu. Skopiuj i wklej ten fragment do pliku z „.C ”rozszerzenie. Skompiluj kod i uruchom go, aby zobaczyć, jak główny() Funkcja i nowy wątek wykonują swoje zadania jednocześnie.

#włączać
#włączać
#włączać
#włączać
void* Thread_Function (void* dane);
int main ()

pThread_T Thread_1;
printf („Tworzenie wątku… \ n”);
pthread_create (& Thread_1, NULL, Thread_Function, NULL);
for (int a = 0; a!= 5; A ++)

printf („z funkcji głównej \ n”);
sen (3);

powrót 0;

/************************************************* ****************/
void* Thread_function (void* n)

for (int a = 0; a!= 5; A ++)

printf („z wątku \ n”);
sen (3);

printf („koniec wątku \ n”);
pthread_exit (n);

Obraz, który widzimy poniżej pthread_create () funkcja równolegle z zadaniem główny() funkcja i wiadomości, które każda z nich wysyła do konsoli polecenia:

Synchronizacja wątków w języku C

W kodzie poprzedniego przykładu czas wykonywania wątku jest krótszy niż czas główny() funkcja i dlatego oba wykonują swoje zadanie poprawnie. Wynika to z opóźnienia 3 sekund, które występuje, gdy główny() Funkcja wychodzi z pętli.
Jeśli jednak czasy wykonywania wątku są dłuższe niż czasy główny() funkcja i jest w pełni wykonana, program kończy się i wszystkie wątki, które zostały utworzone i nadal wykonują zadanie, są automatycznie zamknięte.

Zobaczmy, co stanie się w kodzie poprzedniego przykładu, jeśli ustalimy opóźnienie 1 sekundy na cykl w pętli dla główny() funkcja i jedna z 3 sekund w pętli wątków.

Jak pokazano na zdjęciu, główny() Funkcja zakończyła 5 cykli jej Do pętla, podczas gdy wątek mógł wykonać tylko 3 cykle przed zamknięciem programu.

Zamknięcie wątku bez pełnego wykonywania go może prowadzić do krytycznych problemów w niektórych przypadkach, ponieważ może przechowywać dane generowane przez użytkownika, zapisywać system plików lub urządzenie pamięci lub wykonywać inne zadanie w momencie zakończenia.
Aby uniknąć tych problemów, ważne jest opracowanie mechanizmu „poczekania”, aż wątek zakończy wykonanie przed zamknięciem programu lub wykonania zadania. pthread_join () Funkcja zatrzymuje funkcję, która utworzyła wątek, dopóki ten wątek zakończy wykonanie.

pthread_join () Funkcja przyjmuje dwa argumenty wejściowe. Pierwszy to identyfikator wątków zwrócony przez pthread_create () funkcja po utworzeniu wątku, a drugim argumentem jest wskaźnik do zmiennej, która zwraca status wyjścia wątku.

Następnie używamy kodu z poprzedniego przykładu, ale zastąpimy Do pętla główny() funkcja z pthread_join () funkcja, jak pokazano poniżej:

#włączać
#włączać
#włączać
#włączać
void* Thread_Function (void* dane);
int main ()

pThread_T Thread_1;
printf („Tworzenie wątku… \ n”);
pthread_create (& Thread_1, NULL, Thread_Function, NULL);
pthread_join (Thread_1, null);
powrót 0;

/************************************************* ****************/
void* Thread_function (void* n)

for (int a = 0; a!= 5; A ++)

printf („z wątku \ n”);
sen (3);

printf („koniec wątku \ n”);
pthread_exit (n);

W tym przypadku główny() Funkcja po prostu utworzy wątek i poczekać, aż zakończy swoje zadanie, a następnie zamknie program.

Możliwe błędy, które funkcja pthread_create () może wygenerować i jak je rozpoznać

pthread_create () Funkcja może generować różne błędy, od nieprawidłowych ustawień atrybutów po niewystarczające zasoby systemowe dla nowego wątku.
Gdy funkcja generuje błąd, w zmiennej globalnej przechowywana jest kod identyfikacji błędu liczbowego errno. Ta zmienna i definicje numeryczne dla każdego błędu są zdefiniowane w „Errno.H ”nagłówek.
Poniżej znajduje się opis każdego błędu, który może wystąpić podczas wywoływania pthread_create () funkcja i jej reprezentacja numeryczna zdefiniowana w „Errno.H".

Eagain: Nie ma dostępnych zasobów do utworzenia innego wątku. Reprezentacja liczbowa tego błędu wynosi 35.

Einval: Konfiguracja atrybutów w attr jest nieprawidłowa. Reprezentacja liczbowa tego błędu wynosi 22.

Eperm: Operacja niedozwolona. Ten błąd występuje, gdy nie masz wystarczających uprawnień do ustawienia parametrów atrybutu w attr. Numeryczna reprezentacja tego błędu wynosi 1.

Wniosek

W tym Wskazówka Linux Artykuł, pokazaliśmy, jak korzystać z pthread_create () funkcja tworzenia programów wielozadaniowych z wątkami, które działają równolegle z główną funkcją.

Powiedzieliśmy również, jak kompilować programy, które prawidłowo używają wątków z wiersza poleceń.
Uwzględniliśmy również specjalną sekcję wyjaśniającą znaczenie uwzględnienia czasów wykonywania utworzonych wątków i nauczyliśmy Cię, jak synchronizować wątki z główną funkcją, aby osiągnąć ich prawidłowe wykonanie.