W C ++ ta pula wątków należy zarządzać. C ++ nie ma biblioteki do tworzenia puli wątków i jest zarządzanie. Jest tak prawdopodobnie dlatego, że istnieją różne sposoby tworzenia puli wątków. Tak więc programista C ++ musi utworzyć pulę wątków na podstawie potrzeb.
Co to jest wątek? Wątek to obiekt utworzony z klasy wątku. W normalnym momencie pierwszym argumentem konstruktora wątku jest nazwa funkcji najwyższego poziomu. Reszta argumentów do konstruktora wątku to argumenty dla funkcji. Gdy wątek jest utworzony, funkcja zaczyna się wykonywać. Funkcja C ++ main () to funkcja najwyższego poziomu. Inne funkcje w tym zakresie globalnym są funkcje najwyższego poziomu. Zdarza się, że funkcja main () to wątek, który nie wymaga formalnej deklaracji, tak jak inne wątki. Rozważ następujący program:
#włączać
#włączać
za pomocą przestrzeni nazw Std;
void func ()
Cout << "code for first output" << endl;
Cout << "code for second output" << endl;
int main ()
Thread Thr (FUNC);
thr.dołączyć();
/ * Inne stwierdzenia */
powrót 0;
Wyjście to:
Kod dla pierwszego wyjścia
kod drugiego wyjścia
Zwróć uwagę na włączenie biblioteki wątków, która ma klasę wątków. func () to funkcja najwyższego poziomu. Pierwsza instrukcja w funkcji main (. Następne stwierdzenie w Main () jest oświadczeniem dołączania. Łączy się z wątkiem wątku do korpusu wątku funkcyjnego () w pozycji, w której jest kodowany. Jeśli ta instrukcja jest nieobecna, główna funkcja może zostać wykonana do zakończenia bez ukończenia funkcji wątku. To oznacza problem.
Polecenie podobne do następujących powinno być użyte do uruchomienia programu C ++ 20 wątków dla kompilatora G ++:
G ++ -Std = C ++ 2a Temp.cpp -lpthread -o temp
Ten artykuł wyjaśnia jeden ze sposobów tworzenia i zarządzania pulą wątków w C++.
Treść artykułu
Przykładowe wymagania dotyczące puli wątków
Wymagania dotyczące tej ilustracyjnej puli wątków są proste: istnieją trzy wątki i jeden wątek główny. Wątki są podporządkowane wątkowi głównym. Każdy wątek podrzędny działa ze strukturą danych kolejki. Są więc trzy kolejki: Qu1, Qu2 i Qu3. Biblioteka kolejki, a także biblioteka wątków, muszą być zawarte w programie.
Każda kolejka może mieć więcej niż jedno wywołanie funkcji, ale tej samej funkcji najwyższego poziomu. Oznacza to, że każdy element kolejki dotyczy wywołania funkcji określonej funkcji najwyższego poziomu. Tak więc istnieją trzy różne funkcje najwyższego poziomu: jedna funkcja najwyższego poziomu na wątek. Nazwy funkcji to FN1, FN2 i FN3.
Funkcja wymaga każdej kolejki, różni się tylko ich argumentami. Dla uproszczenia i dla tego przykładu wywołania funkcji nie będą miały argumentu. W rzeczywistości wartość każdej kolejki w tym przykładzie będzie ta sama liczba całkowita: 1 jako wartość dla wszystkich elementów Qu1; 2 jako wartość dla wszystkich elementów Qu2; i 3 jako wartość dla wszystkich elementów Qu3.
Kolejka to struktura First_in-First_Out. Tak więc pierwsze połączenie (numer) wprowadzenie kolejki jest pierwszym, który odejdzie. Po odejściu połączenia (numer), odpowiednia funkcja i jej wątek są wykonywane.
Funkcja Main () jest odpowiedzialna za zasilanie każdej z trzech kolejki, z wywołaniami odpowiednich funkcji, stąd odpowiednie wątki.
Wątek główny jest odpowiedzialny za sprawdzenie, czy w jakiejkolwiek kolejce jest połączenie, a jeśli jest połączenie, wywołuje odpowiednią funkcję przez jej wątek. W tym przykładzie programu, gdy żadna kolejka nie ma żadnego wątku, program kończy się.
Funkcje najwyższego poziomu są proste, dla tego przykładu pedagogicznego są:
void fn1 ()
Cout << "fn1" << endl;
void fn2 ()
Cout << "fn2" << endl;
void fn3 ()
Cout << "fn3" << endl;
Odpowiednie wątki będą to thr1, thr2 i thr3. Wątek główny ma własną funkcję główną. Tutaj każda funkcja ma tylko jedno stwierdzenie. Wyjście funkcji fn1 () to „fn1”. Wyjście funkcji fn2 () to „fn2”. Wyjście funkcji fn3 () to „fn3”.
Na końcu tego artykułu czytelnik może zebrać wszystkie segmenty kodu w tym artykule, aby utworzyć program puli wątków.
Zmienne globalne
Najlepszy program ze zmiennymi globalnymi jest:
#włączać
#włączać
#włączać
za pomocą przestrzeni nazw Std;
kolejkaQu1;
kolejkaQu2;
kolejkaQu3;
wątek thr1;
Wątek thr2;
wątek thr3;
Zmienne kolejki i wątków są zmiennymi globalnymi. Zostały one zadeklarowane bez inicjalizacji lub deklaracji. Po tym w programie powinny być trzy podrzędne funkcje najwyższego poziomu, jak pokazano powyżej.
Biblioteka iostream jest uwzględniona dla obiektu Cout. Biblioteka wątków jest uwzględniona dla wątków. Nazwy wątków to Thr1, Thr2 i Thr3. Biblioteka kolejki jest uwzględniona w kolejce. Nazwy kolejki to Qu1, Qu2 i Qu3. Qu1 odpowiada thr1; Qu2 odpowiada THR2, a Qu3 odpowiada THR3. Kolejka jest jak wektor, ale jest dla FIFO (First_in-First_Out).
Funkcja wątku głównego
Po trzech podrzędnych funkcjach najwyższego poziomu znajdują się funkcja główna w programie. To jest:
void masterfn ()
praca:
if (Qu1.size ()> 0) thr1 = wątek (fn1);
if (Qu2.size ()> 0) thr2 = wątek (fn2);
if (Qu3.size ()> 0) thr3 = wątek (fn3);
if (Qu1.size ()> 0)
Qu1.Muzyka pop();
thr1.dołączyć();
if (Qu2.size ()> 0)
Qu2.Muzyka pop();
thr2.dołączyć();
if (Qu3.size ()> 0)
Qu3.Muzyka pop();
thr3.dołączyć();
if (Qu1.size () == 0 && Qu1.size () == 0 && Qu1.size () == 0)
powrót;
idź do pracy;
Pętla goto uosabia cały kod funkcji. Gdy wszystkie kolejki są puste, funkcja zwraca pustkę, z oświadczeniem „powrót”;.
Pierwszy segment kodu w pętli goto ma trzy stwierdzenia: jeden dla każdej kolejki i odpowiedni wątek. Tutaj, jeśli kolejka nie jest pusta, jego wątek (i odpowiadająca funkcja podrzędnego najwyższego poziomu) jest wykonywana.
Następny segment kodu składa się z trzech konstruktów IF, każdy odpowiadający podrzędnej wątku. Każdy konstrukt IF ma dwa stwierdzenia. Pierwsza instrukcja usuwa numer (dla połączenia), który mógł mieć miejsce w pierwszym segmencie kodu. Następny jest instrukcja łączenia, która zapewnia, że odpowiedni wątek działa na zakończenie.
Ostatnie stwierdzenie w pętli goto kończy funkcję, wychodząc z pętli, jeśli wszystkie kolejki są puste.
Główna funkcja
Po funkcji wątku głównego w programie powinna być funkcją main (), której treści jest:
Qu1.push (1);
Qu1.push (1);
Qu1.push (1);
Qu2.push (2);
Qu2.push (2);
Qu3.push (3);
wątek masterTr (masterfn);
Cout << "Program has started:" << endl;
Masterthr.dołączyć();
Cout << "Program has ended." << endl;
Funkcja Main () jest odpowiedzialna za umieszczanie numerów reprezentujących połączenia w kolejce. Qu1 ma trzy wartości 1; Qu2 ma dwie wartości 2, a Qu3 ma jedną wartość 3. Funkcja main () uruchamia wątek główny i łączy ją do ciała. Wyjście komputera autora to:
Rozpoczął się program:
fn2
fn3
fn1
fn1
fn2
fn1
Program się zakończył.
Wyjście pokazuje nieregularne współbieżne operacje wątków. Zanim funkcja main () dołączy do wątku głównego, wyświetla „Program zaczął:”. Wątek główny wywołuje thr1 dla fn1 (), thr2 dla fn2 () i thr3 dla fn3 (), w tej kolejności. Jednak odpowiednie wyjście zaczyna się od „fn2”, a następnie „fn3”, a następnie „fn1”. Nie ma nic złego w tej początkowej kolejności. Tak działa równolegle, nieregularnie. Reszta ciągów wyjściowych pojawia się, gdy wywołano ich funkcje.
Po przyłączeniu głównego ciała funkcji do wątku głównego, czekał na zakończenie wątku głównego. Aby ukończyć wątek główny, wszystkie kolejki muszą być puste. Każda wartość kolejki odpowiada wykonaniu odpowiedniego wątku. Tak więc, aby każda kolejka stała się pusta, jego wątek musi wykonać przez tę liczbę razy; W kolejce są elementy.
Kiedy wątek główny i jego wątki zostały wykonane i zakończone, główna funkcja nadal wykonuje. I wyświetla: „Program się zakończył.".
Wniosek
Pula wątków to zestaw wątków. Każdy wątek jest odpowiedzialny za wykonanie własnych zadań. Zadania są funkcjami. Teoretycznie zadania zawsze nadchodzą. Tak naprawdę nie kończą się, jak pokazano w powyższym przykładzie. W niektórych praktycznych przykładach dane są udostępniane między wątkami. Aby udostępnić dane, programista potrzebuje wiedzy na temat warunkowego_variable, funkcji asynchronicznej, obietnicy i przyszłości. To jest dyskusja od jakiegoś czasu.