Aby było każde połączenie, potrzebne są dwa wątki. Jeden wątek wywołuje drugi wątek. Dołączenie do wątku oznacza, że podczas gdy wątek wywołujący jest zatrzymany na pozycji i czekał na wywołanie wątku ukończenia wykonania (do końca), zanim będzie kontynuować własną realizację. W pozycji, w której wstrzymuje się wątek, istnieje wyrażenie połączenia. Takie zatrzymanie nazywa się blokowaniem.
Jeśli nazywany wątek trwa zbyt długo, aby zakończyć i prawdopodobnie zrobił to, czego oczekiwał wątek wywoławczy, to wątek wywołania może go odłączyć. Po odłączeniu, jeśli wywołany wątek zakończy się po wątku wywoławczym, nie powinno być problemu. Odłączanie oznacza złamanie połączenia (link).
Przypomnienie sobie czegoś
Wątek to funkcja najwyższego poziomu, która została zamknięta w obiekcie wątku, utworzona z klasy wątku. Ponowanie wątku z funkcją najwyższego poziomu oznacza wywołanie funkcji. Oto prosty program wątków z instrukcją łączenia:
#włączać
#włączać
za pomocą przestrzeni nazw Std;
void func ()
Cout <<"… from thread!" <<'\n';
int main ()
wątek thd (func);
thd.dołączyć();
/* sprawozdania */
powrót 0;
Są tutaj dwa wątki: funkcja obiektu, thd i main (). Główna funkcja jest jak główny wątek. Zwróć uwagę na włączenie biblioteki wątków. Wyjście to:
… Z wątku!
W wierszu polecenia program C ++ 20 z wątkami powinien być dowodzony w następujący sposób dla kompilatora G ++:
G ++ -Std = C ++ 2A próbka.cc -lpthread -o próbka.exe
Treść artykułu
Odłącz () składnię
Składnia odłącza () jest prosta; to jest:
ThreadObject.odłączyć()
Ta funkcja elementu obiektu wątku zwraca void. ThreadObject to obiekt wątku wątku, którego funkcja działa. Gdy funkcja wątku jest uruchomiona, wątek jest nazywany wątkiem wykonującym.
Nić można odłączyć dopiero po połączeniu; W przeciwnym razie wątek jest już w stanie odłączonym.
Niejednoznaczność odłączania się w ciele nić wywołania
W poniższym programie nazywany wątek jest odłączony w korpusie wątku wywołującego:
#włączać
#włączać
#włączać
za pomocą przestrzeni nazw Std;
String Globl = String („Na Ziemi!");
void func (String st)
String Fin = „Living” + ST;
Cout <
int main ()
Thread Thr (FUNC, GLOBL);
thr.dołączyć();
thr.odłączyć();
powrót 0;
Wyjście z komputera autora w czasie wykonywania brzmiało:
Życie na ziemi!
zakończenie wywołane po rzuceniu instancji „std :: System_error”
co (): nieprawidłowy argument
Przerwane (zrzucone rdzeń)
Właściwa oczekiwana wydajność powinna być po prostu:
Życie na ziemi!
Kiedy wątek kończy wykonanie, implementacja uwalnia wszystkie posiadane zasoby. Po dołączeniu wątku korpus wywołania wątku czeka w tym momencie, aż wywołany wątek zakończy swój wykonanie, wówczas korpus wywołania wątku kontynuuje własne wykonanie.
Problem obecności dalszej wydajności polega na tym, że chociaż nazywany wątek mógł wykonać swoje zadanie, jego zasoby nie zostały odebrane, ale funkcja odłączania () spowodowała kontynuowanie wykonywania ciała funkcji wywołania. W przypadku braku funkcji DEACT () nazywany wątek byłby zakończony, a także wszystkie jej zasoby; a wyjście byłaby prostym oczekiwanym jednodmietem.
Aby przekonać czytelnika, rozważ następujący program, który jest taki sam jak powyższe, ale z wypowiedziami dołączonymi () i dystansu ():
#włączać
#włączać
#włączać
za pomocą przestrzeni nazw Std;
String Globl = String („Na Ziemi!");
void func (String st)
String Fin = „Living” + ST;
Cout <
int main ()
Thread Thr (FUNC, GLOBL);
// Thr.dołączyć();
// Thr.odłączyć();
powrót 0;
Dane wyjściowe z komputera autora to:
zakończenie wywoływane bez aktywnego wyjątku
Przerwane (zrzucone rdzeń)
Funkcja main () przebiegła do końca, nie czekając na to, że wątek coś zrobi. I tak wątek nie mógł wyświetlić swojego wyjścia.
Nazwa wątku na globalnym zakresie
Wątek można utworzyć w globalnym zakresie. Poniższy program ilustruje to:
#włączać
#włączać
za pomocą przestrzeni nazw Std;
wątek th;
void func ()
Cout <<"the first line" <Cout <<"the second line" <
int main ()
thr = wątek (func);
thr.dołączyć();
powrót 0;
Wyjście to:
Pierwsza linia
druga linia
Przed funkcją func () jest zdefiniowany w programie; Jest stwierdzenie,
wątek th;
który instaluje wątek, thr. W tym momencie THR nie ma odpowiedniej funkcji. W funkcji Main () pierwszym stwierdzeniem jest:
thr = wątek (func);
Po prawej stronie tego instrukcji tworzy wątek bez nazwy i przypisuje wątek do zmiennej wątku, Thr Thr. W ten sposób THR nabywa funkcję. Następne stwierdzenie dołącza do nazywanego wątku.
Odłączanie się w nazywanym wątku
Lepszym sposobem na oddzielenie wątku jest to, aby to zrobić w korpusie o nazwie nić. W takim przypadku obiekt wątku musiałby zostać utworzony w globalnym zakresie, jak pokazano powyżej. Wówczas stwierdzenie odłączające się będzie w korpusie wywołanego wątku, gdzie powinno odbywać się odłączanie. Poniższy program ilustruje to:
#włączać
#włączać
za pomocą przestrzeni nazw Std;
wątek th;
void func ()
Cout <<"the first line" <thr.odłączyć();
Cout <<"the second line" <
int main ()
thr = wątek (func);
thr.dołączyć();
Cout <<"main() function line" <powrót 0;
Wyjście to:
Pierwsza linia
druga linia
main () linia funkcyjna
W czasie wykonywania nie wydano żadnego komunikatu o błędzie. Instrukcja łączenia () spodziewała się, że wątek zostanie wykonany, zanim nadwozie funkcji Main () będzie kontynuowane. Stało się to pomimo faktu, że zwany wątek został oderwany w środku jego wykonania, z oświadczeniem,
thr.odłączyć();
I tak funkcja Main () (główny wątek) trwała po zakończeniu wywołanego wątku, a wszystkie jej zasoby zostały opublikowane przez implementację. W drugiej połowie wywołanego wątku wywołany wątek został już odłączony, chociaż wątek wywołany wciąż czekał.
Program zaczyna się od włączenia biblioteki iostream dla obiektu Cout. Następnie jest włączenie biblioteki wątków, co jest koniecznością. Następnie występuje instancja wątku, Thr, bez funkcji. Funkcja, której użyje, jest zdefiniowana tuż po. Ta funkcja ma odłączone instrukcje obiektu, Thr w jego ciele.
W ciele funkcyjnym Main () pierwsza instrukcja tworzy wątek funkcji, ale bez nazwy. Ten wątek jest następnie przypisywany do Thr. Tak więc Thr ma teraz funkcję, z zaletą, że został stworzony w globalnym zakresie, aby można było go zobaczyć w FUNC ().
Następne stwierdzenie łączy się z organem funkcyjnym funkcji main () do nazywanego wątku. Wątek został wywołany w pierwszej instrukcji funkcji Main (). W tym momencie nadwozie Main () czeka na to, że nazywany wątek biegnie do końca i wszystkie jego zasoby, choć zostało oderwane na środku. Funkcja Join () wykonuje swój obowiązek, o ile wszystko w zwanym wątku jest uzasadnione.
I tak wykonanie trwa do głównej funkcji po tym, jak nazywany wątek został pomyślnie opuścił, zgodnie z przewidywaniami (z całymi jego zasobami). Dlatego,
„Main () linia funkcyjna”
jest wysyłane po wszystkich wyjściach o nazwie wątku.
Wniosek
Odłączanie wątku oznacza, że wywoływany wątek może nadal wykonywać, a zwany wątek może również nadal wykonywać. To znaczy wątek wywoławczy nie nadal czeka (blok) po dołączeniu. Może to zwiększyć prędkość obu wątków, umożliwiając im bieganie równolegle, a tym samym zwiększenie prędkości całego programu. W takim przypadku najlepiej odłączyć wątek w jego ciele, gdzie komunikacja między nimi nie będzie już wystąpić. Ponadto, aby to osiągnąć, niech zmienna wątków zostanie utworzona w globalnym zakresie bez jej funkcji. W funkcji Main () programu C ++, anonimowy wątek z funkcją zainteresowania można utworzyć i przypisać do zmiennej wątku. Ten krok wywołuje funkcję wątku, a więc wywołuje wątek.
Tak więc, po instrukcji odłączania, oświadczenie Join () nie odgrywa już normalnej roli oczekiwania (blokowanie wątku wywoławczego), choć nadal może czekać. Nie zaleca się oddzielenia wywołanego wątku od wątku wywołania.