Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00367 008441 11062977 na godz. na dobę w sumie
C++. Biblioteka standardowa. Podręcznik programisty. Wydanie II - książka
C++. Biblioteka standardowa. Podręcznik programisty. Wydanie II - książka
Autor: Liczba stron: 1120
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5576-2 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c++ - programowanie
Porównaj ceny (książka, ebook, audiobook).

Lektura obowiązkowa dla każdego programisty C++!

Pomimo olbrzymiej konkurencji ze strony platformy .NET oraz języka Java język C++ wciąż jest niezastąpiony w wielu dziedzinach. Wszędzie tam, gdzie wymagane są najwyższa wydajność, pełna kontrola nad sprzętem oraz przewidywalność, C++ jest bezkonkurencyjny. Biblioteka standardowa C++ to zestaw klas i interfejsów, które w znaczny sposób zwiększają możliwości tego języka. Warto wykorzystać jej potencjał!

Biblioteka standardowa C++ poza wieloma niewątpliwymi zaletami ma jedną poważną wadę - jest trudna do opanowania. Właśnie dlatego potrzebny Ci jest ten podręcznik! W trakcie lektury poznasz nowe elementy języka C++ w wersji 11. Następnie dowiesz się, czym jest standardowa biblioteka szablonów (STL), oraz zobaczysz, jak wykorzystać w codziennej pracy: mapy, multimapy, iteratory, listy oraz wiele innych elementów. Na sam koniec nauczysz się poprawnie korzystać ze współbieżności oraz tworzyć aplikacje obsługujące różne wersje językowe. Każdy z komponentów biblioteki został dokładnie przedstawiony: z opisem przeznaczenia, przykładami oraz problemami, których może przysporzyć. Książka ta jest obowiązkową lekturą każdego programisty C++!

Dzięki tej książce:

Odkryj potęgę C++!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: The C++ Standard Library: A Tutorial and Reference (2nd Edition) Tłumaczenie: Przemysław Szeremiota (wstęp, rozdz. 1 – 6, 9 – 13, 15 – 17, 19, dodatek A), Radosław Meryk (rozdz. 8, 14, 18), Rafał Jońca (rozdz. 7) z wykorzystaniem fragmentów książki „C++. Biblioteka standardowa. Podręcznik programisty” w tłumaczeniu Przemysława Stecia i Rafała Szpotona ISBN: 978-83-246-5576-2 Authorized translation from the English language edition, entitled: THE C++ STANDARD LIBRARY: A TUTORIAL AND REFERENCE, Second Edition; ISBN 0321623215; by Nicolai M. Josuttis; published by Pearson Education, Inc, publishing as Addison Wesley. Copyright © 2012 Pearson Education, Inc. All rights reserved. No part of this book may by reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc. Polish language edition published by HELION S.A. Copyright © 2014. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/cpbsp2.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/cpbsp2 Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:264)ci Przedmowa do drugiego wydania Podzi(cid:246)kowania do drugiego wydania Przedmowa do pierwszego wydania Podzi(cid:246)kowania do pierwszego wydania 1. O ksi(cid:241)(cid:276)ce 1.1. Dlaczego powsta(cid:228)a ta ksi(cid:241)(cid:276)ka? 1.2. Co nale(cid:276)y wiedzie(cid:232) przed przyst(cid:241)pieniem do lektury tej ksi(cid:241)(cid:276)ki? 1.3. Styl i struktura ksi(cid:241)(cid:276)ki 1.4. Jak czyta(cid:232) t(cid:246) ksi(cid:241)(cid:276)k(cid:246)? 1.5. Stan obecny 1.6. Przyk(cid:228)adowy kod i dodatkowe informacje 2. Wprowadzenie do j(cid:246)zyka C++ i biblioteki standardowej 2.1. Historia standardów C++ 2.1.1. Typowe pytania o standard C++11 2.1.2. Zgodno(cid:264)(cid:232) pomi(cid:246)dzy C++11 i C++98 2.2. Z(cid:228)o(cid:276)ono(cid:264)(cid:232) algorytmów a notacja O 3. Nowe elementy j(cid:246)zyka 3.1. Nowe elementy j(cid:246)zyka C++11 3.1.1. Istotne pomniejsze porz(cid:241)dki sk(cid:228)adniowe 3.1.2. Automatyczna dedukcja typu ze s(cid:228)owem auto 3.1.3. Jednolita sk(cid:228)adnia inicjalizacji i listy inicjalizacyjne 3.1.4. P(cid:246)tle zakresowe 3.1.5. Semantyka przeniesienia i referencje do r-warto(cid:264)ci 3.1.6. Nowe litera(cid:228)y napisowe 3.1.7. S(cid:228)owo noexcept 3.1.8. S(cid:228)owo constexpr 17 19 21 23 25 25 26 26 30 30 30 31 31 32 34 34 37 37 37 38 39 41 43 48 49 51 Kup książkęPoleć książkę 6 SPIS TRE(cid:285)CI 3.1.9. Nowe elementy szablonów 3.1.10. Lambdy 3.1.11. S(cid:228)owo decltype 3.1.12. Nowa sk(cid:228)adnia deklaracji funkcji 3.1.13. Klasy wyliczeniowe 3.1.14. Nowe typy podstawowe 3.2. Starsze „nowo(cid:264)ci” j(cid:246)zyka C++ 3.2.1. Jawna inicjalizacja typów podstawowych 3.2.2. Definicja funkcji main() 4. Poj(cid:246)cia ogólne 4.1. Przestrze(cid:254) nazw std 4.2. Pliki nag(cid:228)ówkowe 4.3. Obs(cid:228)uga b(cid:228)(cid:246)dów i wyj(cid:241)tków 4.3.1. Standardowe klasy wyj(cid:241)tków 4.3.2. Sk(cid:228)adowe klas wyj(cid:241)tków 4.3.3. Przekazywanie wyj(cid:241)tków z u(cid:276)yciem klasy exception_ptr 4.3.4. Zg(cid:228)aszanie wyj(cid:241)tków standardowych 4.3.5. Tworzenie klas pochodnych standardowych klas wyj(cid:241)tków 4.4. Obiekty wywo(cid:228)ywalne 4.5. Wielow(cid:241)tkowo(cid:264)(cid:232) i wspó(cid:228)bie(cid:276)no(cid:264)(cid:232) 4.6. Alokatory 5. Narz(cid:246)dzia 5.1. Pary i krotki 5.1.1. Pary 5.1.2. Krotki 5.1.3. Wej(cid:264)cie-wyj(cid:264)cie dla krotek 5.1.4. Konwersje pomi(cid:246)dzy krotkami a parami 5.2. Inteligentne wska(cid:274)niki 5.2.1. Klasa shared_ptr 5.2.2. Klasa weak_ptr 5.2.3. Niepoprawne stosowanie wska(cid:274)ników wspó(cid:228)dzielonych 5.2.4. Klasy wska(cid:274)ników s(cid:228)abych i wspó(cid:228)dzielonych w szczegó(cid:228)ach 5.2.5. Klasa unique_ptr 5.2.6. Klasa unique_ptr w szczegó(cid:228)ach 5.2.7. Klasa auto_ptr 5.2.8. Podsumowanie inteligentnych wska(cid:274)ników 5.3. Ograniczenia liczbowe 5.4. Cechy typowe i narz(cid:246)dzia pracy z typami 5.4.1. Przeznaczenie cech typowych 5.4.2. Cechy typowe w szczegó(cid:228)ach 5.4.3. Uj(cid:246)cia referencyjne 5.4.4. Uj(cid:246)cia typów funkcyjnych 5.5. Funkcje pomocnicze 5.5.1. Obliczanie warto(cid:264)ci minimalnej oraz maksymalnej 5.5.2. Zamiana dwóch warto(cid:264)ci 5.5.3. Dodatkowe operatory porównania 5.6. Statyczna arytmetyka liczb wymiernych — klasa ratio 51 53 57 57 58 58 59 63 63 65 65 67 68 68 72 80 80 81 82 83 85 87 88 88 96 101 103 103 104 112 118 120 127 140 143 144 145 152 152 156 163 164 165 165 167 169 170 Kup książkęPoleć książkę C++. BIBLIOTEKA STANDARDOWA. PODR(cid:265)CZNIK PROGRAMISTY 7 5.7. Zegary i czasomierze 5.8. Pliki nag(cid:228)ówkowe cstddef , cstdlib oraz cstring 5.8.1. Definicje w pliku cstddef 5.8.2. Definicje w pliku cstdlib 5.8.3. Definicje w pliku cstring 6. Standardowa biblioteka szablonów (STL) 6.1. Sk(cid:228)adniki biblioteki STL 6.2. Kontenery 6.2.1. Kontenery sekwencyjne 6.2.2. Kontenery asocjacyjne 6.2.3. Kontenery nieporz(cid:241)dkuj(cid:241)ce 6.2.4. Tablice asocjacyjne 6.2.5. Inne kontenery 6.2.6. Adaptatory kontenerów 5.7.1. Przegl(cid:241)d biblioteki chrono 5.7.2. Okresy 5.7.3. Zegary i punkty w czasie 5.7.4. Funkcje daty i czasu j(cid:246)zyka C i standardu POSIX 5.7.5. Czasowe wstrzymywanie wykonania 174 174 176 180 189 191 192 193 193 195 197 198 199 201 210 214 219 221 222 223 6.3.1. Inne przyk(cid:228)ady u(cid:276)ycia kontenerów asocjacyjnych i nieporz(cid:241)dkuj(cid:241)cych 228 6.3.2. Kategorie iteratorów 233 234 238 242 245 245 247 249 251 251 252 253 256 258 259 259 261 263 267 267 273 274 277 278 278 279 6.10.1. Definicja obiektów funkcyjnych 6.10.2. Predefiniowane obiekty funkcyjne 6.10.3. Wi(cid:241)zanie wywo(cid:228)ania 6.10.4. Obiekty funkcyjne i wi(cid:241)zanie kontra lambdy 6.5.1. Iteratory wstawiaj(cid:241)ce 6.5.2. Iteratory strumieni 6.5.3. Iteratory odwrotne 6.5.4. Iteratory przenosz(cid:241)ce 6.7.1. Usuwanie elementów 6.7.2. Algorytmy modyfikuj(cid:241)ce kontenery asocjacyjne i nieporz(cid:241)dkuj(cid:241)ce 6.7.3. Algorytmy a funkcje sk(cid:228)adowe 6.8. Funkcje jako argumenty algorytmów 6.8.1. Przyk(cid:228)ady u(cid:276)ycia funkcji jako argumentów algorytmów 6.8.2. Predykaty 6.4. Algorytmy 6.4.1. Zakresy 6.4.2. Obs(cid:228)uga wielu zakresów 6.5. Adaptatory iteratorów 6.11. Elementy kontenerów 6.11.1. Wymagania wobec elementów kontenerów 6.11.2. Semantyka warto(cid:264)ci a semantyka referencji 6.6. W(cid:228)asne uogólnione operacje na kontenerach 6.7. Algorytmy modyfikuj(cid:241)ce 6.3. Iteratory 6.9. Stosowanie lambd 6.10. Obiekty funkcyjne Kup książkęPoleć książkę 8 SPIS TRE(cid:285)CI 6.12. Obs(cid:228)uga b(cid:228)(cid:246)dów i wyj(cid:241)tków wewn(cid:241)trz biblioteki STL 6.12.1. Obs(cid:228)uga b(cid:228)(cid:246)dów 6.12.2. Obs(cid:228)uga wyj(cid:241)tków 6.13. Rozbudowa biblioteki STL 6.13.1. Integrowanie dodatkowych typów 6.13.2. Dziedziczenie po typach STL 7. Kontenery STL 7.1. Wspólne cechy i operacje kontenerów 7.1.1. Wspólne cechy kontenerów 7.1.2. Wspólne operacje kontenerów 7.1.3. Typy kontenerów 7.2. Tablice 7.2.1. Mo(cid:276)liwo(cid:264)ci tablic 7.2.2. Operacje dotycz(cid:241)ce tablic 7.2.3. U(cid:276)ywanie klas array jako zwyk(cid:228)ych tablic 7.2.4. Obs(cid:228)uga wyj(cid:241)tków 7.2.5. Interfejs krotki 7.2.6. Przyk(cid:228)ady u(cid:276)ycia tablic 7.3. Wektory 7.3.1. Mo(cid:276)liwo(cid:264)ci wektorów 7.3.2. Operacje na wektorach 7.3.3. U(cid:276)ywanie wektorów jako zwyk(cid:228)ych tablic 7.3.4. Obs(cid:228)uga wyj(cid:241)tków 7.3.5. Przyk(cid:228)ady u(cid:276)ycia wektorów 7.3.6. Klasa vector bool 7.4. Kolejki o dwóch ko(cid:254)cach 7.4.1. Mo(cid:276)liwo(cid:264)ci kolejek deque 7.4.2. Operacje na kolejkach deque 7.4.3. Obs(cid:228)uga wyj(cid:241)tków 7.4.4. Przyk(cid:228)ady u(cid:276)ycia kolejek deque 7.5. Listy 7.5.1. Mo(cid:276)liwo(cid:264)ci list 7.5.2. Operacje na listach 7.5.3. Obs(cid:228)uga wyj(cid:241)tków 7.5.4. Przyk(cid:228)ady u(cid:276)ycia list 7.6. Listy jednokierunkowe 7.6.1. Mo(cid:276)liwo(cid:264)ci list jednokierunkowych 7.6.2. Operacje na listach jednokierunkowych 7.6.3. Obs(cid:228)uga wyj(cid:241)tków 7.6.4. Przyk(cid:228)ady u(cid:276)ycia list jednokierunkowych 7.7. Zbiory i wielozbiory 7.7.1. Mo(cid:276)liwo(cid:264)ci zbiorów i wielozbiorów 7.7.2. Operacje na zbiorach i wielozbiorach 7.7.3. Obs(cid:228)uga wyj(cid:241)tków 7.7.4. Przyk(cid:228)ady u(cid:276)ycia zbiorów i wielozbiorów 7.7.5. Przyk(cid:228)ad okre(cid:264)lania kryterium sortowania podczas wykonywania 7.8. Mapy oraz multimapy 7.8.1. Mo(cid:276)liwo(cid:264)ci map oraz multimap 7.8.2. Operacje na mapach oraz multimapach 280 280 282 286 286 287 289 290 290 290 297 298 298 301 305 305 306 306 307 308 310 316 317 318 319 321 322 323 327 327 328 329 330 336 337 338 339 341 351 351 352 354 355 364 364 367 369 370 371 Kup książkęPoleć książkę C++. BIBLIOTEKA STANDARDOWA. PODR(cid:265)CZNIK PROGRAMISTY 7.8.3. Zastosowanie map jako tablic asocjacyjnych 7.8.4. Obs(cid:228)uga wyj(cid:241)tków 7.8.5. Przyk(cid:228)ady u(cid:276)ycia map i multimap 7.8.6. Przyk(cid:228)ad z mapami, (cid:228)a(cid:254)cuchami oraz definiowaniem kryterium sortowania podczas wykonywania 7.9. Kontenery nieuporz(cid:241)dkowane 7.9.1. Mo(cid:276)liwo(cid:264)ci kontenerów nieuporz(cid:241)dkowanych 7.9.2. Tworzenie i kontrolowanie kontenerów nieuporz(cid:241)dkowanych 7.9.3. Inne operacje kontenerów nieuporz(cid:241)dkowanych 7.9.4. Interfejs kube(cid:228)ków 7.9.5. Zastosowanie map nieuporz(cid:241)dkowanych jako tablic asocjacyjnych 7.9.6. Obs(cid:228)uga wyj(cid:241)tków 7.9.7. Przyk(cid:228)ady u(cid:276)ycia kontenerów nieuporz(cid:241)dkowanych 7.10. Inne kontenery STL 7.10.1. (cid:227)a(cid:254)cuchy jako kontenery STL 7.10.2. Zwyk(cid:228)e tablice jako kontenery STL 7.11. Implementacja semantyki referencji 7.12. Kiedy stosowa(cid:232) poszczególne kontenery? 8. Sk(cid:228)adowe kontenerów STL 8.1. Definicje typów 8.2. Operacje tworzenia, kopiowania i niszczenia 8.3. Operacje niemodyfikuj(cid:241)ce 8.3.1. Operacje dotycz(cid:241)ce rozmiaru 8.3.2. Operacje porównania 8.3.3. Operacje niemodyfikuj(cid:241)ce kontenerów asocjacyjnych i nieuporz(cid:241)dkowanych 8.4. Operacje przypisania 8.5. Bezpo(cid:264)redni dost(cid:246)p do elementów 8.6. Operacje generuj(cid:241)ce iteratory 8.7. Wstawianie i usuwanie elementów 8.7.1. Wstawianie pojedynczych elementów 8.7.2. Wstawianie wielu elementów 8.7.3. Usuwanie elementów 8.7.4. Zmiana rozmiaru 8.8. Specjalne funkcje sk(cid:228)adowe list 8.8.1. Specjalne funkcje sk(cid:228)adowe list i list forward_list 8.8.2. Specjalne funkcje sk(cid:228)adowe list forward_list 8.9. Interfejsy strategii obs(cid:228)ugi kontenerów 8.9.1. Niemodyfikuj(cid:241)ce funkcje strategii 8.9.2. Modyfikuj(cid:241)ce funkcje strategii 8.9.3. Interfejs dost(cid:246)pu do kube(cid:228)ków kontenerów nieuporz(cid:241)dkowanych 8.10. Obs(cid:228)uga alokatorów 8.10.1. Podstawowe sk(cid:228)adowe alokatorów 8.10.2. Konstruktory z opcjonalnymi parametrami alokatorów 9 382 384 384 388 391 394 397 404 411 412 413 413 421 422 423 425 428 435 435 438 442 442 443 444 446 448 450 452 452 457 459 462 462 462 466 470 470 471 473 474 474 474 Kup książkęPoleć książkę 10 9. Iteratory STL 9.1. Pliki nag(cid:228)ówkowe iteratorów 9.2. Kategorie iteratorów 9.2.1. Iteratory wyj(cid:264)ciowe 9.2.2. Iteratory wej(cid:264)ciowe 9.2.3. Iteratory post(cid:246)puj(cid:241)ce 9.2.4. Iteratory dwukierunkowe 9.2.5. Iteratory dost(cid:246)pu swobodnego 9.2.6. Problem z inkrementacj(cid:241) i dekrementacj(cid:241) iteratorów wektorów 9.3. Pomocnicze funkcje iteratorów 9.3.1. Funkcja advance() 9.3.2. Funkcje next() i prev() 9.3.3. Funkcja distance() 9.3.4. Funkcja iter_swap() 9.4. Adaptatory iteratorów 9.4.1. Iteratory odwrotne 9.4.2. Iteratory wstawiaj(cid:241)ce 9.4.3. Iteratory strumieni 9.4.4. Iteratory przenosz(cid:241)ce 9.5. Cechy typowe iteratorów 9.5.1. Definiowanie uogólnionych funkcji dla iteratorów 9.6. Iteratory definiowane przez u(cid:276)ytkownika 10. Obiekty funkcyjne STL i lambdy 10.1. Poj(cid:246)cie obiektów funkcyjnych 10.1.1. Obiekty funkcyjne jako kryteria sortowania 10.1.2. Obiekty funkcyjne ze stanem wewn(cid:246)trznym 10.1.3. Warto(cid:264)(cid:232) zwracana algorytmu for_each() 10.1.4. Predykaty a obiekty funkcyjne 10.2. Predefiniowane obiekty funkcyjne i obiekty wi(cid:241)zania wywo(cid:228)ania 10.2.1. Predefiniowane obiekty funkcyjne 10.2.2. Adaptatory i obiekty wi(cid:241)zania wywo(cid:228)ania 10.2.3. Obiekty funkcyjne definiowane przez u(cid:276)ytkownika dla adaptatorów funkcji SPIS TRE(cid:285)CI 479 479 479 480 481 483 484 484 487 488 488 490 492 493 494 495 499 506 511 512 514 516 521 521 522 524 527 529 531 531 532 10.3. Lambdy 10.2.4. Zarzucone adaptatory funkcji 541 542 544 544 10.3.1. Lambdy a wi(cid:241)zanie wywo(cid:228)ania 545 10.3.2. Lambdy a stanowe obiekty funkcyjne 10.3.3. Lambdy z wywo(cid:228)aniami funkcji globalnych i sk(cid:228)adowych 547 10.3.4. Lambdy jako funkcje mieszaj(cid:241)ce, sortuj(cid:241)ce i kryteria równowa(cid:276)no(cid:264)ci 549 551 551 552 552 553 564 566 570 11.2.1. Krótkie wprowadzenie 11.2.2. Klasyfikacja algorytmów 11.3. Funkcje pomocnicze 11.4. Algorytm for_each() 11.5. Algorytmy niemodyfikuj(cid:241)ce 11. Algorytmy STL 11.1. Pliki nag(cid:228)ówkowe algorytmów 11.2. Przegl(cid:241)d algorytmów Kup książkęPoleć książkę C++. BIBLIOTEKA STANDARDOWA. PODR(cid:265)CZNIK PROGRAMISTY 11.5.1. Zliczanie elementów 11.5.2. Warto(cid:264)(cid:232) minimalna i maksymalna 11.5.3. Wyszukiwanie elementów 11.5.4. Porównywanie zakresów 11.5.5. Predykaty zakresowe 11.6. Algorytmy modyfikuj(cid:241)ce 11.6.1. Kopiowanie elementów 11.6.2. Przenoszenie elementów mi(cid:246)dzy zakresami 11.6.3. Przekszta(cid:228)cenia i kombinacje elementów 11.6.4. Wymienianie elementów 11.6.5. Przypisywanie nowych warto(cid:264)ci 11.6.6. Zast(cid:246)powanie elementów 11.7. Algorytmy usuwaj(cid:241)ce 11.7.1. Usuwanie okre(cid:264)lonych warto(cid:264)ci 11.7.2. Usuwanie powtórze(cid:254) 11.8. Algorytmy mutuj(cid:241)ce 11.8.1. Odwracanie kolejno(cid:264)ci elementów 11.8.2. Przesuni(cid:246)cia cykliczne elementów 11.8.3. Permutacje elementów 11.8.4. Tasowanie elementów 11.8.5. Przenoszenie elementów na pocz(cid:241)tek 11.8.6. Podzia(cid:228) na dwa podzakresy 11.9. Algorytmy sortuj(cid:241)ce 11.9.1. Sortowanie wszystkich elementów 11.9.2. Sortowanie cz(cid:246)(cid:264)ciowe 11.9.3. Sortowanie wed(cid:228)ug n-tego elementu 11.9.4. Algorytmy stogowe 11.10. Algorytmy przeznaczone dla zakresów posortowanych 11.10.1. Wyszukiwanie elementów 11.10.2. Scalanie elementów 11.11. Algorytmy numeryczne 11.11.1. Obliczanie warto(cid:264)ci 11.11.2. Konwersje warto(cid:264)ci wzgl(cid:246)dnych i bezwzgl(cid:246)dnych 12. Kontenery specjalne 12.1. Stosy 12.1.1. Interfejs 12.1.2. Przyk(cid:228)ad u(cid:276)ycia stosów 12.1.3. W(cid:228)asna klasa stosu 12.1.4. Klasa stack w szczegó(cid:228)ach 12.2. Kolejki 12.2.1. Interfejs 12.2.2. Przyk(cid:228)ad u(cid:276)ycia kolejek 12.2.3. W(cid:228)asna klasa kolejki 12.2.4. Klasa queue w szczegó(cid:228)ach 12.3. Kolejki priorytetowe 12.3.1. Interfejs 12.3.2. Przyk(cid:228)ad u(cid:276)ycia kolejek priorytetowych 12.3.3. Klasa priority_queue w szczegó(cid:228)ach 11 570 572 574 586 593 599 600 603 605 608 610 613 615 616 619 623 623 624 627 629 631 633 634 635 637 640 642 645 646 651 659 660 663 667 668 669 669 670 673 673 675 675 676 676 676 678 678 679 Kup książkęPoleć książkę 12 SPIS TRE(cid:285)CI 12.4. Adaptatory kontenerów w szczegó(cid:228)ach 12.4.1. Definicje typów 12.4.2. Konstruktory 12.4.3. Konstruktory pomocnicze dla kolejki priorytetowej 12.4.4. Operacje 12.5. Kontener bitset 12.5.1. Przyk(cid:228)ady u(cid:276)ycia kontenerów bitset 12.5.2. Klasa bitset w szczegó(cid:228)ach 13. (cid:227)a(cid:254)cuchy znakowe 13.1. Przeznaczenie klas (cid:228)a(cid:254)cuchów znakowych 13.1.1. Przyk(cid:228)ad pierwszy: konstruowanie tymczasowej nazwy pliku 13.1.2. Przyk(cid:228)ad drugi: wyodr(cid:246)bnianie s(cid:228)ów i wypisywanie ich w odwrotnej kolejno(cid:264)ci 13.2. Opis klas reprezentuj(cid:241)cych (cid:228)a(cid:254)cuchy znakowe 13.2.1. Typy (cid:228)a(cid:254)cuchów znakowych 13.2.2. Przegl(cid:241)d funkcji sk(cid:228)adowych 13.2.3. Konstruktory oraz destruktory 13.2.4. (cid:227)a(cid:254)cuchy znakowe zwyk(cid:228)e oraz j(cid:246)zyka C 13.2.5. Rozmiar oraz pojemno(cid:264)(cid:232) 13.2.6. Dost(cid:246)p do elementów 13.2.7. Porównania 13.2.8. Modyfikatory 13.2.9. Konkatenacja (cid:228)a(cid:254)cuchów znakowych oraz ich fragmentów 13.2.10. Operatory wej(cid:264)cia-wyj(cid:264)cia 13.2.11. Poszukiwanie oraz odnajdywanie (cid:228)a(cid:254)cuchów znakowych 13.2.12. Warto(cid:264)(cid:232) npos 13.2.13. Konwersje liczbowe 13.2.14. Obs(cid:228)uga iteratorów (cid:228)a(cid:254)cuchów znakowych 13.2.15. Obs(cid:228)uga standardów narodowych 13.2.16. Wydajno(cid:264)(cid:232) 13.2.17. (cid:227)a(cid:254)cuchy znakowe a wektory 13.3. Klasa string w szczegó(cid:228)ach 13.3.1. Definicje typu oraz warto(cid:264)ci statyczne 13.3.2. Funkcje sk(cid:228)adowe s(cid:228)u(cid:276)(cid:241)ce do tworzenia, kopiowania oraz usuwania (cid:228)a(cid:254)cuchów znakowych 13.3.3. Funkcje dotycz(cid:241)ce rozmiaru oraz pojemno(cid:264)ci 13.3.4. Porównania 13.3.5. Dost(cid:246)p do znaków 13.3.6. Tworzenie (cid:228)a(cid:254)cuchów znakowych j(cid:246)zyka C oraz tablic znaków 13.3.7. Funkcje do modyfikacji zawarto(cid:264)ci (cid:228)a(cid:254)cuchów znakowych 13.3.8. Wyszukiwanie 13.3.9. (cid:227)(cid:241)czenie (cid:228)a(cid:254)cuchów znakowych 13.3.10. Funkcje wej(cid:264)cia-wyj(cid:264)cia 13.3.11. Konwersje liczbowe 13.3.12. Funkcje tworz(cid:241)ce iteratory 13.3.13. Obs(cid:228)uga alokatorów 680 680 681 681 682 684 686 688 689 690 691 695 699 699 700 704 705 707 708 710 711 714 715 716 719 720 722 728 730 730 731 731 732 734 735 737 739 739 748 752 753 754 755 756 Kup książkęPoleć książkę C++. BIBLIOTEKA STANDARDOWA. PODR(cid:265)CZNIK PROGRAMISTY 14. Wyra(cid:276)enia regularne 14.1. Interfejs dopasowywania i wyszukiwania wyra(cid:276)e(cid:254) regularnych 14.2. Obs(cid:228)uga podwyra(cid:276)e(cid:254) 14.3. Iteratory dopasowa(cid:254) 14.4. Iteratory podci(cid:241)gów 14.5. Zast(cid:246)powanie wyra(cid:276)e(cid:254) regularnych 14.6. Flagi wyra(cid:276)e(cid:254) regularnych 14.7. Wyj(cid:241)tki zwi(cid:241)zane z wyra(cid:276)eniami regularnymi 14.8. Gramatyka wyra(cid:276)e(cid:254) regularnych ECMAScript 14.9. Inne gramatyki 14.10. Sygnatury podstawowych funkcji 15. Obs(cid:228)uga wej(cid:264)cia-wyj(cid:264)cia z wykorzystaniem klas strumieniowych 15.1. Podstawy strumieni wej(cid:264)cia-wyj(cid:264)cia 15.1.1. Obiekty strumieni 15.1.2. Klasy strumieni 15.1.3. Globalne obiekty strumieni 15.1.4. Operatory strumieniowe 15.1.5. Manipulatory 15.1.6. Prosty przyk(cid:228)ad 15.2. Podstawowe obiekty oraz klasy strumieniowe 15.2.1. Klasy oraz hierarchia klas 15.2.2. Globalne obiekty strumieni 15.2.3. Pliki nag(cid:228)ówkowe 15.3. Standardowe operatory strumieniowe oraz 15.3.1. Operator wyj(cid:264)ciowy 15.3.2. Operator wej(cid:264)ciowy 15.3.3. Operacje wej(cid:264)cia-wyj(cid:264)cia dla specjalnych typów 15.4. Stany strumieni 15.4.1. Sta(cid:228)e s(cid:228)u(cid:276)(cid:241)ce do okre(cid:264)lania stanów strumieni 15.4.2. Funkcje sk(cid:228)adowe operuj(cid:241)ce na stanie strumieni 15.4.3. Warunki wykorzystuj(cid:241)ce stan strumienia oraz warto(cid:264)ci logiczne 15.4.4. Stan strumienia i wyj(cid:241)tki 15.5. Standardowe funkcje wej(cid:264)cia-wyj(cid:264)cia 15.5.1. Funkcje sk(cid:228)adowe s(cid:228)u(cid:276)(cid:241)ce do pobierania danych 15.5.2. Funkcje sk(cid:228)adowe s(cid:228)u(cid:276)(cid:241)ce do wysy(cid:228)ania danych 15.5.3. Przyk(cid:228)ad u(cid:276)ycia 15.5.4. Obiekty sentry 15.6. Manipulatory 15.6.1. Przegl(cid:241)d dost(cid:246)pnych manipulatorów 15.6.2. Sposób dzia(cid:228)ania manipulatorów 15.6.3. Manipulatory definiowane przez u(cid:276)ytkownika 15.7. Formatowanie 15.7.1. Znaczniki formatu 15.7.2. Format warto(cid:264)ci logicznych 15.7.3. Szeroko(cid:264)(cid:232) pola, znak wype(cid:228)nienia oraz wyrównanie 15.7.4. Znak warto(cid:264)ci dodatnich oraz du(cid:276)e litery 15.7.5. Podstawa numeryczna 13 759 759 762 768 769 771 773 777 779 781 782 785 786 786 787 787 788 788 789 790 790 794 795 796 796 798 799 802 802 803 805 808 812 813 817 818 819 820 820 822 824 825 825 827 828 831 832 Kup książkęPoleć książkę 14 SPIS TRE(cid:285)CI 15.7.6. Notacja zapisu liczb zmiennoprzecinkowych 15.7.7. Ogólne definicje formatuj(cid:241)ce 15.8. Umi(cid:246)dzynarodawianie 15.9. Dost(cid:246)p do plików 15.9.1. Klasy strumieni plikowych 15.9.2. Semantyka r-warto(cid:264)ci i przeniesienia dla strumieni plikowych 15.9.3. Znaczniki pliku 15.9.4. Dost(cid:246)p swobodny 15.9.5. Deskryptory plików 15.10. Klasy strumieni dla (cid:228)a(cid:254)cuchów znakowych 15.10.1. Klasy strumieni dla (cid:228)a(cid:254)cuchów znakowych 15.10.2. Semantyka przeniesienia dla strumieni z (cid:228)a(cid:254)cuchów znakowych 15.10.3. Klasy strumieni dla warto(cid:264)ci typu char* 15.11. Operatory wej(cid:264)cia-wyj(cid:264)cia dla typów zdefiniowanych przez u(cid:276)ytkownika 15.11.1. Implementacja operatorów wyj(cid:264)ciowych 15.11.2. Implementacja operatorów wej(cid:264)ciowych 15.11.3. Operacje wej(cid:264)cia-wyj(cid:264)cia przy u(cid:276)yciu funkcji pomocniczych 15.11.4. Znaczniki formatu definiowane przez u(cid:276)ytkownika 15.11.5. Konwencje operatorów wej(cid:264)cia-wyj(cid:264)cia definiowanych przez u(cid:276)ytkownika 15.12. (cid:227)(cid:241)czenie strumieni wej(cid:264)ciowych oraz wyj(cid:264)ciowych 15.12.1. Lu(cid:274)ne powi(cid:241)zanie przy u(cid:276)yciu tie() 15.12.2. (cid:263)cis(cid:228)e powi(cid:241)zanie przy u(cid:276)yciu buforów strumieni 15.12.3. Przekierowywanie strumieni standardowych 15.12.4. Strumienie s(cid:228)u(cid:276)(cid:241)ce do odczytu oraz zapisu 15.13. Klasy bufora strumienia 15.13.1. Interfejsy buforów strumieni 15.13.2. Iteratory wykorzystywane z buforem strumienia 15.13.3. Bufory strumienia definiowane przez u(cid:276)ytkownika 15.14. Kwestie wydajno(cid:264)ci 15.14.1. Synchronizacja ze standardowymi strumieniami j(cid:246)zyka C 15.14.2. Buforowanie w buforach strumieni 15.14.3. Bezpo(cid:264)rednie wykorzystanie buforów strumieni 16. Umi(cid:246)dzynarodowienie 16.1. Kodowanie znaków i zestawy znaków 16.1.1. Znaki wielobajtowe i znaki szerokiego zakresu 16.1.2. Ró(cid:276)ne zestawy znaków 16.1.3. Obs(cid:228)uga zestawów znaków w C++ 16.1.4. Cechy znaków 16.1.5. Umi(cid:246)dzynarodawianie specjalnych znaków 16.2. Poj(cid:246)cie obiektów ustawie(cid:254) lokalnych 16.2.1. Wykorzystywanie ustawie(cid:254) lokalnych 16.2.2. Aspekty ustawie(cid:254) lokalnych 16.3. Klasa locale w szczegó(cid:228)ach 16.4. Klasa facet w szczegó(cid:228)ach 16.4.1. Formatowanie warto(cid:264)ci liczbowych 16.4.2. Formatowanie warto(cid:264)ci pieni(cid:246)(cid:276)nych 16.4.3. Formatowanie czasu oraz daty 834 836 837 838 838 842 843 847 849 850 851 854 855 858 858 860 862 863 866 867 867 869 871 872 874 875 877 881 893 893 894 895 899 901 901 902 903 904 908 909 911 917 919 922 923 928 938 Kup książkęPoleć książkę C++. BIBLIOTEKA STANDARDOWA. PODR(cid:265)CZNIK PROGRAMISTY 16.4.4. Klasyfikacja oraz konwersja znaków 16.4.5. Sortowanie (cid:228)a(cid:254)cuchów znakowych 16.4.6. Lokalizacja komunikatów 17. Komponenty numeryczne 17.1. Liczby i rozk(cid:228)ady losowe 17.1.1. Pierwszy przyk(cid:228)ad 17.1.2. Mechanizmy losowo(cid:264)ci 17.1.3. Mechanizmy losowo(cid:264)ci w szczegó(cid:228)ach 17.1.4. Rozk(cid:228)ady 17.1.5. Dystrybucje w szczegó(cid:228)ach 17.2. Liczby zespolone 17.2.1. complex w uj(cid:246)ciu ogólnym 17.2.2. Przyk(cid:228)ad wykorzystania klasy reprezentuj(cid:241)cej liczby zespolone 17.2.3. Funkcje operuj(cid:241)ce na liczbach zespolonych 17.2.4. Klasa complex w szczegó(cid:228)ach 17.3. Globalne funkcje numeryczne 17.4. Klasa valarray 18. Wspó(cid:228)bie(cid:276)no(cid:264)(cid:232) 18.1. Interfejs wysokiego poziomu: async() i futury 18.1.1. Pierwszy przyk(cid:228)ad u(cid:276)ycia funkcji async() i futur 18.1.2. Przyk(cid:228)ad oczekiwania na dwa zadania 18.1.3. Wspó(cid:228)dzielone futury 18.2. Interfejs niskiego poziomu: w(cid:241)tki i promesy 18.2.1. Klasa std::thread 18.2.2. Promesy 18.2.3. Klasa packaged_task 18.3. Uruchamianie w(cid:241)tku w szczegó(cid:228)ach 18.3.1. Funkcja async() w szczegó(cid:228)ach 18.3.2. Futury w szczegó(cid:228)ach 18.3.3. Futury wspó(cid:228)dzielone w szczegó(cid:228)ach 18.3.4. Klasa std::promise w szczegó(cid:228)ach 18.3.5. Klasa std::packaged_task w szczegó(cid:228)ach 18.3.6. Klasa std::thread w szczegó(cid:228)ach 18.3.7. Przestrze(cid:254) nazw this_thread 18.4. Synchronizacja w(cid:241)tków, czyli najwi(cid:246)kszy problem wspó(cid:228)bie(cid:276)no(cid:264)ci 18.4.1. Uwaga na wspó(cid:228)bie(cid:276)no(cid:264)(cid:232)! 18.4.2. Przyczyna problemu jednoczesnego dost(cid:246)pu do danych 18.4.3. Zakres problemu, czyli co mo(cid:276)e pój(cid:264)(cid:232) (cid:274)le? 18.4.4. Mechanizmy pozwalaj(cid:241)ce na rozwi(cid:241)zanie problemów 18.5. Muteksy i blokady 18.5.1. Wykorzystywanie muteksów i blokad 18.5.2. Muteksy i blokady w szczegó(cid:228)ach 18.5.3. Wywo(cid:228)ywanie funkcjonalno(cid:264)ci raz dla wielu w(cid:241)tków 18.6. Zmienne warunkowe 18.6.1. Przeznaczenie zmiennych warunkowych 18.6.2. Pierwszy kompletny przyk(cid:228)ad wykorzystania zmiennych warunkowych 15 945 959 960 963 963 964 969 972 973 977 981 981 982 984 992 997 999 1001 1003 1003 1013 1017 1021 1021 1027 1029 1030 1031 1033 1034 1035 1036 1038 1039 1040 1041 1042 1043 1047 1049 1049 1058 1062 1063 1064 1065 Kup książkęPoleć książkę 16 18.6.3. Wykorzystanie zmiennych warunkowych do zaimplementowania kolejki dla wielu w(cid:241)tków 18.6.4. Zmienne warunkowe w szczegó(cid:228)ach 18.7. Atomowe typy danych 18.7.1. Przyk(cid:228)ad u(cid:276)ycia atomowych typów danych 18.7.2. Atomowe typy danych i ich interfejs wysokiego poziomu w szczegó(cid:228)ach 18.7.3. Interfejs atomowych typów danych w stylu j(cid:246)zyka C 18.7.4. Niskopoziomowy interfejs atomowych typów danych 19. Alokatory 19.1. Wykorzystywanie alokatorów przez programistów aplikacji 19.2. Alokator definiowany przez u(cid:276)ytkownika 19.3. Wykorzystywanie alokatorów przez programistów bibliotek Bibliografia Grupy i fora dyskusyjne Ksi(cid:241)(cid:276)ki i strony WWW Skorowidz SPIS TRE(cid:285)CI 1067 1070 1072 1073 1077 1080 1081 1085 1085 1086 1088 1093 1093 1094 1099 Kup książkęPoleć książkę 18 Wspó(cid:228)bie(cid:276)no(cid:264)(cid:232) Nowoczesne architektury systemów zazwyczaj umo(cid:276)liwiaj(cid:241) uruchamianie wielu zada(cid:254) i wielu w(cid:241)tków jednocze(cid:264)nie. Wykorzystanie wielu w(cid:241)tków mo(cid:276)e przy- czyni(cid:232) si(cid:246) do znacznej poprawy czasu realizacji programów, zw(cid:228)aszcza w kom- puterach, których procesory s(cid:241) wyposa(cid:276)one w wiele rdzeni. Jednak równoleg(cid:228)e uruchamianie programów wprowadza równie(cid:276) nowe wy- zwania. Zamiast wykonywa(cid:232) instrukcje jedna po drugiej, mo(cid:276)na uruchomi(cid:232) wiele instrukcji jednocze(cid:264)nie. Mo(cid:276)e to prowadzi(cid:232) do problemów z jednoczesnym dost(cid:246)- pem do tych samych zasobów. W takich sytuacjach operacje tworzenia, czytania, pisania i usuwania mog(cid:241) odbywa(cid:232) si(cid:246) w nieoczekiwanej kolejno(cid:264)ci, co mo(cid:276)e prowa- dzi(cid:232) do nieoczekiwanych rezultatów. W rzeczywisto(cid:264)ci wspó(cid:228)bie(cid:276)ny dost(cid:246)p do danych z wielu w(cid:241)tków (cid:228)atwo mo(cid:276)e sta(cid:232) si(cid:246) koszmarem. Jednym z najprostszych problemów, jakie mog(cid:241) si(cid:246) pojawi(cid:232), s(cid:241) zakleszczenia, kiedy to w(cid:241)tki wzajemnie na siebie czekaj(cid:241). Przed wprowadzeniem standardu C++11 j(cid:246)zyk C++ ani standardowa biblioteka j(cid:246)zyka nie zawiera(cid:228)y obs(cid:228)ugi wspó(cid:228)bie(cid:276)no(cid:264)ci, jednak poszczególne implementacje mog(cid:228)y zawiera(cid:232) pewne mechanizmy obs(cid:228)ugi wspó(cid:228)bie(cid:276)no(cid:264)ci. Wraz z powsta- niem C++11 to si(cid:246) zmieni(cid:228)o. Usprawniono zarówno rdze(cid:254) j(cid:246)zyka, jak i bibliotek(cid:246), wprowadzaj(cid:241)c obs(cid:228)ug(cid:246) programowania wspó(cid:228)bie(cid:276)nego (patrz podrozdzia(cid:228) 4.5): (cid:120) W podstawowym j(cid:246)zyku zdefiniowano model pami(cid:246)ci, który gwarantuje, (cid:276)e aktualizacje dwóch ró(cid:276)nych obiektów wykorzystywanych przez dwa ró(cid:276)ne w(cid:241)tki s(cid:241) niezale(cid:276)ne od siebie. Wprowadzono równie(cid:276) nowe s(cid:228)owo kluczowe thread_local do definiowania zmiennych z warto(cid:264)ciami specyficznymi dla w(cid:241)tków. (cid:120) Biblioteka zapewnia obecnie wsparcie dla uruchamiania wielu w(cid:241)tków. Umo(cid:276)liwia równie(cid:276) przekazywanie argumentów, zwracanie warto(cid:264)ci i zg(cid:228)a- szanie wyj(cid:241)tków poza granicami w(cid:241)tków. Zapewnia tak(cid:276)e mechanizmy do synchronizacji wielu w(cid:241)tków. Dzi(cid:246)ki temu mo(cid:276)emy synchronizowa(cid:232) zarów- no przep(cid:228)yw sterowania, jak i dost(cid:246)p do danych. Kup książkęPoleć książkę 1002 18. WSPÓ(cid:224)BIE(cid:297)NO(cid:285)(cid:251) Biblioteka zapewnia wsparcie dla wspó(cid:228)bie(cid:276)no(cid:264)ci na wielu poziomach. Na przy- k(cid:228)ad interfejs wysokiego poziomu umo(cid:276)liwia rozpocz(cid:246)cie w(cid:241)tku, przekazanie do niego argumentów i obs(cid:228)ug(cid:246) wyników i wyj(cid:241)tków. Interfejs ten bazuje na kilku in- terfejsach niskiego poziomu dla ka(cid:276)dego z tych aspektów. Z drugiej strony, ist- niej(cid:241) równie(cid:276) w(cid:228)asno(cid:264)ci niskiego poziomu, takie jak muteksy lub atomowe typy da- nych (ang. atomics) obs(cid:228)uguj(cid:241)ce swobodne kolejkowanie pami(cid:246)ci (ang. relaxed memory order). W tym rozdziale zaprezentowano te funkcje biblioteczne. Nale(cid:276)y zauwa(cid:276)y(cid:232), (cid:276)e temat wspó(cid:228)bie(cid:276)no(cid:264)ci oraz opis bibliotek, które j(cid:241) obs(cid:228)uguj(cid:241), mo(cid:276)e wype(cid:228)ni(cid:232) ca(cid:228)e tomy. Z tego powodu w tym rozdziale zaprezentuj(cid:246) ogólne poj(cid:246)cia i typowe przyk(cid:228)ady dla przeci(cid:246)tnego programisty, z g(cid:228)ównym naciskiem na interfejsy wy- sokiego poziomu. Po szczegó(cid:228)owe informacje, zw(cid:228)aszcza dotycz(cid:241)ce trudnych problemów funkcji i interfejsów niskiego poziomu, odsy(cid:228)am do wymienionych tutaj konkretnych ksi(cid:241)(cid:276)ek i artyku(cid:228)ów. Moj(cid:241) pierwsz(cid:241) i najwa(cid:276)niejsz(cid:241) rekomendacj(cid:241) dla ca(cid:228)ego te- matu wspó(cid:228)bie(cid:276)no(cid:264)ci jest ksi(cid:241)(cid:276)ka C++ Concurrency in Action autorstwa Anthony’ego Williamsa (patrz [Williams:C++Conc]). Anthony jest jednym z kluczowych (cid:264)wiatowych ekspertów w tej dziedzinie, powstanie tego rozdzia(cid:228)u bez jego wk(cid:228)adu nie by(cid:228)oby mo(cid:276)liwe. Nie tylko przejrza(cid:228) niniejsz(cid:241) ksi(cid:241)(cid:276)k(cid:246), ale tak(cid:276)e dostarczy(cid:228) pierwszej implementacji standardowej biblio- teki obs(cid:228)ugi wspó(cid:228)bie(cid:276)no(cid:264)ci (patrz [JustThread]), napisa(cid:228) kilka artyku(cid:228)ów oraz prze- kaza(cid:228) cenne opinie. Wszystko to pomog(cid:228)o mi w przedstawieniu tego tematu — mam nadziej(cid:246) w przydatny sposób. Dodatkowo jednak chcia(cid:228)bym podzi(cid:246)kowa(cid:232) kilku innym ekspertom w dziedzinie wspó(cid:228)bie(cid:276)no(cid:264)ci, którzy pomogli mi w napi- saniu tego rozdzia(cid:228)u: Hansowi Boehmowi, Scottowi Meyersowi, Bartoszowi Milew- skiemu, Lawrence’owi Crowlowi i Peterowi Sommerladowi. Niniejszy rozdzia(cid:228) jest zorganizowany w nast(cid:246)puj(cid:241)cy sposób: (cid:120) Najpierw zaprezentuj(cid:246) ró(cid:276)ne sposoby uruchamiania wielu w(cid:241)tków. Po wpro- wadzeniu w tematyk(cid:246) interfejsów zarówno wysokopoziomowych, jak i nisko- poziomowych zaprezentuj(cid:246) szczegó(cid:228)owe informacje zwi(cid:241)zane z uruchamianiem w(cid:241)tków. (cid:120) W podrozdziale 18.4 zamieszczono szczegó(cid:228)owe omówienie problemu syn- chronizowania w(cid:241)tków. G(cid:228)ównym problemem jest jednoczesny dost(cid:246)p do da- nych. (cid:120) Na koniec omówiono ró(cid:276)ne funkcje s(cid:228)u(cid:276)(cid:241)ce do synchronizacji w(cid:241)tków i jed- noczesnego dost(cid:246)pu do danych: (cid:120) Muteksy i blokady (patrz podrozdzia(cid:228) 18.5), z funkcj(cid:241) call_once() w(cid:228)(cid:241)cznie (patrz punkt 18.5.3). (cid:120) Zmienne warunkowe (patrz podrozdzia(cid:228) 18.6). (cid:120) Atomowe typy danych (patrz podrozdzia(cid:228) 18.7). Kup książkęPoleć książkę 18.1. INTERFEJS WYSOKIEGO POZIOMU: ASYNC() I FUTURY 1003 18.1. Interfejs wysokiego poziomu: async() i futury Dla pocz(cid:241)tkuj(cid:241)cych najlepszym punktem wyj(cid:264)cia do uruchomienia programu z ob- s(cid:228)ug(cid:241) wielu w(cid:241)tków jest skorzystanie z wysokopoziomowego interfejsu C++ biblio- teki standardowej dostarczonego za po(cid:264)rednictwem wywo(cid:228)ania std::async() oraz klasy std::future : (cid:120) async() zapewnia interfejs umo(cid:276)liwiaj(cid:241)cy uruchomienie fragmentu funkcjonal- no(cid:264)ci — obiektu wywo(cid:228)ywalnego (ang. callable object) (patrz podrozdzia(cid:228) 4.4) — w tle, w osobnym w(cid:241)tku. (cid:120) Klasa future pozwala czeka(cid:232) na zako(cid:254)czenie w(cid:241)tku i zapewnia dost(cid:246)p do jego wyników: zwróconej warto(cid:264)ci lub wyj(cid:241)tku. W tym rozdziale szczegó(cid:228)owo zaprezentowano ten interfejs wysokiego poziomu. Temat rozszerzono o wprowadzenie do klasy std::shared_future , która pozwala na oczekiwanie na zako(cid:254)czenie w(cid:241)tku i przetwarzanie jego wyników w wielu miejscach. 18.1.1. Pierwszy przyk(cid:228)ad u(cid:276)ycia funkcji async() i futur Przypu(cid:264)(cid:232)my, (cid:276)e musimy obliczy(cid:232) sum(cid:246) dwóch operandów zwracan(cid:241) przez dwa wywo(cid:228)ania funkcji. Standardowy sposób zaprogramowania tej funkcjonalno(cid:264)ci jest nast(cid:246)puj(cid:241)cy: func1() + func2() Oznacza to, (cid:276)e przetwarzanie operandów odbywa si(cid:246) sekwencyjnie. Program naj- pierw wywo(cid:228)uje funkcj(cid:246) func1(), a nast(cid:246)pnie wywo(cid:228)uje funkcj(cid:246) func2() lub od- wrotnie (zgodnie z regu(cid:228)ami j(cid:246)zyka kolejno(cid:264)(cid:232) jest niezdefiniowana). W obu przy- padkach ca(cid:228)kowity czas przetwarzania wynosi: czas wykonywania funkcji func1() plus czas wykonywania funkcji func2() plus czas wyliczenia sumy. Obecnie, kiedy sprz(cid:246)t wieloprocesorowy jest dost(cid:246)pny niemal wsz(cid:246)dzie, mo(cid:276)e- my wykonywa(cid:232) obliczenia wydajniej. Mo(cid:276)emy przynajmniej spróbowa(cid:232) uruchomi(cid:232) funkcje func1() i func2() równolegle. Dzi(cid:246)ki temu ca(cid:228)kowity czas przetwarzania b(cid:246)dzie równy sumie d(cid:228)u(cid:276)szego z czasów przetwarzania funkcji func1() i func2() plus czas wyliczenia sumy. Poni(cid:276)ej zaprezentowano pierwszy program realizuj(cid:241)cy obliczenia w taki sposób: // concurrency/async1.cpp #include future #include thread #include chrono #include random #include iostream #include exception using namespace std; Kup książkęPoleć książkę 1004 18. WSPÓ(cid:224)BIE(cid:297)NO(cid:285)(cid:251) int doSomething (char c) { // generator liczb losowych (wykorzystuje c jako ziarno do uzyskania ró(cid:298)nych sekwencji) std::default_random_engine dre(c); std::uniform_int_distribution int id(10,1000); // p(cid:266)tla wy(cid:286)wietlaj(cid:261)ca znak po up(cid:225)ywie losowego czasu for (int i=0; i 10; ++i) { this_thread::sleep_for(chrono::milliseconds(id(dre))); cout.put(c).flush(); } return c; } int func1 () { return doSomething( . ); } int func2 () { return doSomething( + ); } int main() { std::cout uruchomienie funkcji func1() w tle, a funkcji func2() na pierwszym planie: std::endl; // uruchomienie funkcji func1() asynchronicznie (teraz, pó(cid:296)niej lub nigdy): std::future int result1(std::async(func1)); int result2 = func2(); // wywo(cid:225)anie funkcji func2() synchronicznie (tu i teraz) // wy(cid:286)wietlenie wyniku (oczekiwanie na zako(cid:276)czenie funkcji func1() i dodanie jej wyniku do zmiennej result2 int result = result1.get() + result2; std::cout wynik sumy func1()+func2(): result std::endl; } W celu wizualizacji tego, co si(cid:246) dzieje, zasymulowali(cid:264)my z(cid:228)o(cid:276)one przetwarzanie wewn(cid:241)trz funkcji func1() i func2() poprzez wywo(cid:228)anie funkcji doSomething(), która od czasu do czasu wy(cid:264)wietla znak przekazany za pomoc(cid:241) argumentu1 i na koniec zwraca warto(cid:264)(cid:232) przekazanego znaku jako warto(cid:264)(cid:232) int. „Od czasu do czasu” zaimplementowano poprzez wykorzystanie generatora liczb losowych, który jest odpowiedzialny za obliczenie interwa(cid:228)ów. Interwa(cid:228)y te s(cid:241) wykorzystywane w funkcji std::this_thread::sleep_for() do wstrzymywania bie(cid:276)(cid:241)cego w(cid:241)tku (szcze- gó(cid:228)owe informacje na temat liczb losowych mo(cid:276)na znale(cid:274)(cid:232) w podrozdziale 17.1, natomiast szczegó(cid:228)owe informacje dotycz(cid:241)ce funkcji sleep_for()mo(cid:276)na znale(cid:274)(cid:232) w punkcie 18.3.7). Zwró(cid:232)my uwag(cid:246), (cid:276)e aby generowane sekwencje liczb losowych 1 Generowanie wyj(cid:264)cia przez wspó(cid:228)bie(cid:276)ne w(cid:241)tki jest mo(cid:276)liwe, ale mo(cid:276)e skutkowa(cid:232) przeplataniem si(cid:246) znaków z ró(cid:276)nych w(cid:241)tków (patrz podrozdzia(cid:228) 4.5). Kup książkęPoleć książkę 18.1. INTERFEJS WYSOKIEGO POZIOMU: ASYNC() I FUTURY 1005 by(cid:228)y ró(cid:276)ne, potrzebujemy unikatowego ziarna (ang. seed), które nale(cid:276)y przekaza(cid:232) do konstruktora generatora liczb losowych (w tym przyk(cid:228)adzie w tej roli u(cid:276)yli- (cid:264)my znaku c). Zamiast wywo(cid:228)ania: int result = func1() + func2(); wywo(cid:228)ujemy: std::future int result1(std::async(func1)); int result2 = func2(); int result = result1.get() + result2; Zatem najpierw próbujemy uruchomi(cid:232) funkcj(cid:246) func1() w tle, u(cid:276)ywaj(cid:241)c wywo(cid:228)ania std::async(), a nast(cid:246)pnie przypisujemy wynik do obiektu klasy std::future: std::future int result1(std::async(func1)); W powy(cid:276)szej instrukcji wywo(cid:228)anie async() próbuje natychmiast uruchomi(cid:232) przeka- zan(cid:241) funkcjonalno(cid:264)(cid:232) asynchronicznie, w osobnym w(cid:241)tku. Tak wi(cid:246)c w idealnej sytu- acji funkcja func1() rozpoczyna dzia(cid:228)anie w tym miejscu bez blokowania funkcji main(). Zwracany obiekt futury jest konieczny z dwóch powodów: 1. Umo(cid:276)liwia dost(cid:246)p do „przysz(cid:228)ego” wyniku funkcji przekazanej do funkcji async(). Ten wynik mo(cid:276)e by(cid:232) zwrócon(cid:241) warto(cid:264)ci(cid:241) albo wyj(cid:241)tkiem. Obiekt futury jest wyspecjalizowany wed(cid:228)ug typu zwracanej warto(cid:264)ci uruchomionej funkcjonalno(cid:264)ci. Je(cid:264)li uruchomiono tylko zadanie w tle, które niczego nie zwraca, to musi to by(cid:232) obiekt std::future void . 2. Nale(cid:276)y zapewni(cid:232), aby przekazana funkcjonalno(cid:264)(cid:232) zosta(cid:228)a pr(cid:246)dzej lub pó(cid:274)niej wywo(cid:228)ana. Zwró(cid:232)my uwag(cid:246), (cid:276)e napisa(cid:228)em: funkcja async() próbuje uruchomi(cid:232) przekazan(cid:241) funkcjonalno(cid:264)(cid:232). Je(cid:264)li si(cid:246) to nie stanie, musimy wymusi(cid:232) na obiekcie futury uruchomienie w chwili, gdy potrzebujemy wyniku lub gdy chcemy si(cid:246) upewni(cid:232), (cid:276)e funkcjonalno(cid:264)(cid:232) zosta(cid:228)a wykonana. Z tego powodu obiekt futury jest potrzebny nawet wtedy, gdy nie jeste(cid:264)my zainteresowani wynikiem funk- cjonalno(cid:264)ci uruchomionej w tle. Do wymiany danych pomi(cid:246)dzy miejscem, z którego uruchomiono funkcjonalno(cid:264)(cid:232) i z którego ni(cid:241) zarz(cid:241)dzamy, a zwróconym obiektem futury s(cid:228)u(cid:276)y tzw. stan wspó(cid:228)- dzielony (patrz podrozdzia(cid:228) 18.3). Oczywi(cid:264)cie mo(cid:276)na równie(cid:276) (zazwyczaj tak b(cid:246)dziemy robi(cid:232)) u(cid:276)y(cid:232) s(cid:228)owa klu- czowego auto do zadeklarowania futury (w tym przyk(cid:228)adzie chcia(cid:228)em to jawnie zademonstrowa(cid:232)): auto result1(std::async(func1)); Po drugie, funkcj(cid:246) func2() uruchamiamy na pierwszym planie. Jest to zwyczajne synchroniczne wywo(cid:228)anie funkcji, dlatego program blokuje si(cid:246) w tym miejscu: int result2 = func2(); Zatem je(cid:264)li funkcja func1() zosta(cid:228)a pomy(cid:264)lnie uruchomiona przez funkcj(cid:246) async() i jeszcze si(cid:246) nie zako(cid:254)czy(cid:228)a, to funkcje func1() i func2() s(cid:241) teraz uruchomione jed- nocze(cid:264)nie. Kup książkęPoleć książkę 1006 18. WSPÓ(cid:224)BIE(cid:297)NO(cid:285)(cid:251) W trzeciej kolejno(cid:264)ci przetwarzamy sum(cid:246). To jest moment, kiedy potrzebujemy wyniku funkcji func1(). Aby go uzyska(cid:232), wywo(cid:228)ujemy funkcj(cid:246) get() w odniesieniu do zwróconego obiektu futury: int result = result1.get() + result2; W momencie wywo(cid:228)ywania funkcji get() mo(cid:276)e zachodzi(cid:232) jedna z trzech sytuacji: 1. Je(cid:264)li funkcja func1() zosta(cid:228)a uruchomiona za pomoc(cid:241) funkcji async() w od- dzielnym w(cid:241)tku i ju(cid:276) si(cid:246) zako(cid:254)czy(cid:228)a, to natychmiast uzyskamy jej wynik. 2. Je(cid:264)li funkcja func1() zosta(cid:228)a uruchomiona, ale jeszcze si(cid:246) nie zako(cid:254)czy(cid:228)a, to funkcja get() blokuje si(cid:246) i czeka na jej zako(cid:254)czenie. Na koniec zwraca wynik. 3. Je(cid:264)li funkcja func1() jeszcze nie zosta(cid:228)a uruchomiona, b(cid:246)dzie zmuszona do natychmiastowego uruchomienia i tak jak dla synchronicznego wywo(cid:228)ania funkcji get() zablokuje si(cid:246) w oczekiwaniu na wynik. To zachowanie jest bardzo wa(cid:276)ne, poniewa(cid:276) zapewnia ono dzia(cid:228)anie programu tak(cid:276)e w (cid:264)rodowisku jednow(cid:241)tkowym oraz w przypadku, kiedy funkcja async() z jakiego(cid:264) powodu nie mog(cid:228)a uruchomi(cid:232) nowego w(cid:241)tku. Wywo(cid:228)anie funkcji async() nie gwarantuje, (cid:276)e przekazana do niej funkcjo- nalno(cid:264)(cid:232) zostanie rozpocz(cid:246)ta i si(cid:246) zako(cid:254)czy. Je(cid:264)li w(cid:241)tek jest dost(cid:246)pny, to zostanie uruchomiony, ale je(cid:264)li nie — ze wzgl(cid:246)du na to, (cid:276)e okre(cid:264)lone (cid:264)rodowisko nie ob- s(cid:228)uguje wielow(cid:241)tkowo(cid:264)ci lub nie ma dost(cid:246)pnych wi(cid:246)cej w(cid:241)tków — wtedy wywo- (cid:228)anie zostanie odroczone do momentu, kiedy jawnie stwierdzimy, (cid:276)e potrzebu- jemy jego wyniku (poprzez wywo(cid:228)anie get()), lub po prostu kiedy b(cid:246)dziemy chcieli, aby okre(cid:264)lona funkcjonalno(cid:264)(cid:232) zosta(cid:228)a wykonana (poprzez wywo(cid:228)anie wait() — patrz punkt 18.1.1). A zatem kombinacja instrukcji: std::future int result1(std::async(func1)); oraz result1.get() pozwala zoptymalizowa(cid:232) program w taki sposób, (cid:276)e je(cid:264)li to b(cid:246)dzie mo(cid:276)liwe, funkcja func1() b(cid:246)dzie dzia(cid:228)a(cid:232) wspó(cid:228)bie(cid:276)nie w czasie, gdy s(cid:241) przetwarzane nast(cid:246)pne in- strukcje w g(cid:228)ównym w(cid:241)tku. Je(cid:264)li nie ma mo(cid:276)liwo(cid:264)ci jej wspó(cid:228)bie(cid:276)nego urucho- mienia, b(cid:246)dzie wywo(cid:228)ana sekwencyjnie w momencie, gdy zostanie wywo(cid:228)ana funkcja get(). Oznacza to, (cid:276)e w ka(cid:276)dym przypadku uzyskujemy gwarancj(cid:246), (cid:276)e po wywo(cid:228)aniu get() funkcja func1() b(cid:246)dzie wywo(cid:228)ana asynchronicznie lub syn- chronicznie. W zwi(cid:241)zku z tym ten program mo(cid:276)e generowa(cid:232) dwa rodzaje wyników. Je(cid:264)li funkcja async() mo(cid:276)e pomy(cid:264)lnie uruchomi(cid:232) funkcj(cid:246) func1(), wynik mo(cid:276)e mie(cid:232) nast(cid:246)puj(cid:241)c(cid:241) posta(cid:232): uruchomienie funkcji func1() w tle, a funkcji func2() na pierwszym planie: ++..++++.++.+.+..... wynik sumy func1()+func2(): 89 Kup książkęPoleć książkę 18.1. INTERFEJS WYSOKIEGO POZIOMU: ASYNC() I FUTURY 1007 Je(cid:264)li funkcja async() nie mog(cid:228)a uruchomi(cid:232) funkcji func1(), funkcja ta zostanie uru- chomiona po funkcji func2(), w momencie wywo(cid:228)ania funkcji get(). W zwi(cid:241)zku z tym program b(cid:246)dzie mia(cid:228) nast(cid:246)puj(cid:241)cy wynik: uruchomienie funkcji func1() w tle, a funkcji func2() na pierwszym planie: ++++++++++.......... wynik sumy func1()+func2(): 89 Tak wi(cid:246)c na podstawie pierwszego przyk(cid:228)adu mo(cid:276)emy zdefiniowa(cid:232) ogólny spo- sób na to, by program dzia(cid:228)a(cid:228) szybciej: mo(cid:276)emy zmodyfikowa(cid:232) program w taki sposób, aby móg(cid:228) korzysta(cid:232) ze wspó(cid:228)bie(cid:276)no(cid:264)ci, je(cid:264)li jest dost(cid:246)pna na platformie, na której uruchomiono program, ale by móg(cid:228) dzia(cid:228)a(cid:232) tak(cid:276)e w (cid:264)rodowiskach jed- now(cid:241)tkowych. W tym celu nale(cid:276)y wykona(cid:232) nast(cid:246)puj(cid:241)ce czynno(cid:264)ci: (cid:120) umie(cid:264)ci(cid:232) w programie dyrektyw(cid:246) #include future ; (cid:120) przekaza(cid:232) funkcjonalno(cid:264)(cid:232), które mo(cid:276)e by(cid:232) uruchomiona samodzielnie jako wywo(cid:228)ywalny obiekt, do funkcji std::async(); (cid:120) przypisa(cid:232) wynik do obiektu future ZwracanyTyp ; (cid:120) wywo(cid:228)a(cid:232) funkcj(cid:246) get() na rzecz obiektu future , kiedy b(cid:246)dzie potrzebny nam wynik lub kiedy b(cid:246)dziemy chcieli mie(cid:232) pewno(cid:264)(cid:232), (cid:276)e uruchomiona funkcjonalno(cid:264)(cid:232) si(cid:246) zako(cid:254)czy(cid:228)a. Nale(cid:276)y jednak pami(cid:246)ta(cid:232), (cid:276)e dotyczy to tylko takiej sytuacji, kiedy nie wyst(cid:246)puje wy(cid:264)cig o dane, co oznacza, (cid:276)e dwa w(cid:241)tki równocze(cid:264)nie korzystaj(cid:241) z tych samych da- nych, co mo(cid:276)e by(cid:232) przyczyn(cid:241) niezdefiniowanego zachowania (patrz punkt 18.4.1). Zwró(cid:232)my uwag(cid:246), (cid:276)e bez wywo(cid:228)ania funkcji get() nie mamy gwarancji, czy funkcja func1() kiedykolwiek b(cid:246)dzie wywo(cid:228)ana. Zgodnie z tym, co napisano wcze- (cid:264)niej, je(cid:264)li funkcja async() nie mo(cid:276)e uruchomi(cid:232) przekazanej funkcjonalno(cid:264)ci na- tychmiast, odracza wywo(cid:228)anie do chwili jawnego za(cid:276)(cid:241)dania wyniku przekazanej funkcjonalno(cid:264)ci za pomoc(cid:241) funkcji get() (lub wait()). Jednak bez takiego (cid:276)(cid:241)dania zako(cid:254)czenie dzia(cid:228)ania funkcji main() spowoduje zako(cid:254)czenie programu nawet bez wywo(cid:228)ania w(cid:241)tku dzia(cid:228)aj(cid:241)cego w tle. Zwró(cid:232)my tak(cid:276)e uwag(cid:246), (cid:276)e musimy zadba(cid:232) o to, aby (cid:276)(cid:241)danie wyniku funk- cjonalno(cid:264)ci rozpocz(cid:246)tej za pomoc(cid:241) funkcji async() nie nast(cid:241)pi(cid:228)o wcze(cid:264)niej, ni(cid:276) to konieczne. Na przyk(cid:228)ad poni(cid:276)sza „optymalizacja” prawdopodobnie nie przyniesie spodziewanego efektu: std::future int result1(std::async(func1)); int result = func2() + result1.get(); // wywo(cid:225)anie funkcji func2() mo(cid:298)e nast(cid:261)pi(cid:252) po zako(cid:276)czeniu dzia(cid:225)ania funkcji func1() Poniewa(cid:276) kolejno(cid:264)(cid:232) wykonywania dzia(cid:228)a(cid:254) po prawej stronie drugiej instrukcji jest niezdefiniowana, wywo(cid:228)anie result1.get() mo(cid:276)e nast(cid:241)pi(cid:232) przed wywo(cid:228)aniem func2(), a zatem b(cid:246)dzie to ponownie przetwarzanie sekwencyjne. Aby uzyska(cid:232) najlepszy efekt, ogólnie rzecz bior(cid:241)c, dystans pomi(cid:246)dzy wywo- (cid:228)aniami async() i get() powinien by(cid:232) jak najwi(cid:246)kszy. Mo(cid:276)na równie(cid:276) zastosowa(cid:232) warunki okre(cid:264)lone w [N3194:Futures]: Wczesne wywo(cid:228)anie i pó(cid:274)ne zwrócenie wyniku. Je(cid:264)li operacja przekazana do funkcji async() nie zwraca (cid:276)adnej warto(cid:264)ci, funkcja async() zwraca obiekt future void , który jest cz(cid:246)(cid:264)ciow(cid:241) specjalizacj(cid:241) obiektu future . W takim przypadku wywo(cid:228)anie get() nie zwraca niczego: Kup książkęPoleć książkę 1008 18. WSPÓ(cid:224)BIE(cid:297)NO(cid:285)(cid:251) std::future void f(std::async(func)); // próba asynchronicznego wywo(cid:225)ania funkcji ... f.get(); // oczekiwanie na zako(cid:276)czenie funkcji (zwraca void) Na koniec zwró(cid:232)my uwag(cid:246), (cid:276)e obiekt przekazany do funkcji async() mo(cid:276)e by(cid:232) obiektem wywo(cid:228)ywalnym dowolnego typu: funkcj(cid:241), funkcj(cid:241) sk(cid:228)adow(cid:241), obiektem funk- cyjnym lub wyra(cid:276)eniem lambda (patrz podrozdzia(cid:228) 4.4). Zatem mo(cid:276)emy równie(cid:276) przekaza(cid:232) funkcjonalno(cid:264)(cid:232) inline jako wyra(cid:276)enie lambda. Funkcjonalno(cid:264)(cid:232) ta b(cid:246)dzie dzia(cid:228)a(cid:228)a we w(cid:228)asnym w(cid:241)tku (patrz punkt 3.1.10): std::async([]{ ... }) // próba uruchomienia kodu ... asynchronicznie Strategie uruchamiania Mo(cid:276)emy zapobiec odroczeniu uruchomienia funkcjonalno(cid:264)ci przekazanej do funkcji async() poprzez jawne przekazanie strategii uruchamiania2. W ten sposób mo(cid:276)emy nakaza(cid:232) funkcji async(), aby ta uruchomi(cid:228)a przekazan(cid:241) funkcjonalno(cid:264)(cid:232) dok(cid:228)adnie w momencie wywo(cid:228)ania: // wymuszenie asynchronicznego uruchomienia funkcji func1(); w przypadku niepowodzenia zg(cid:225)aszany // jest wyj(cid:261)tek std::system_error std::future long result1= std::async(std::launch::async, func1); Je(cid:264)li wywo(cid:228)anie asynchroniczne nie jest mo(cid:276)liwe w tym miejscu, program zg(cid:228)osi wyj(cid:241)tek std::system_error (patrz punkt 4.3.1) z kodem b(cid:228)(cid:246)du resource_unavailable_ (cid:180)try_again. Jest to odpowiednik kodu b(cid:228)(cid:246)du POSIX errno EAGAIN (patrz punkt 4.3.2). Przy u(cid:276)yciu strategii uruchamiania async nie musimy wywo(cid:228)ywa(cid:232) funkcji get(), poniewa(cid:276) je(cid:264)li czas (cid:276)ycia zwróconej futury dobiegnie ko(cid:254)ca, program zaczeka na zako(cid:254)czenie dzia(cid:228)ania funkcji func1(). Je(cid:264)li wi(cid:246)c nie wywo(cid:228)amy funkcji get(), to po opuszczeniu zakresu obiektu futury (tutaj b(cid:246)dzie nim koniec funkcji main()) program b(cid:246)dzie czeka(cid:228) na zako(cid:254)czenie zadania dzia(cid:228)aj(cid:241)cego w tle. Niemniej jednak wywo(cid:228)anie funkcji get() zanim program zako(cid:254)czy dzia(cid:228)anie, sprawia, (cid:276)e zacho- wanie kodu staje si(cid:246) czytelniejsze. Je(cid:264)li nigdzie nie przypiszemy wyniku std::async(std::launch::async,...), obiekt wywo(cid:228)uj(cid:241)cy zablokuje si(cid:246) do czasu zako(cid:254)czenia przekazanej funkcjonalno(cid:264)ci. W takim przypadku b(cid:246)dzie to równoznaczne z wywo(cid:228)aniem synchronicznym3. W podobny sposób mo(cid:276)emy wymusi(cid:232) odroczone wywo(cid:228)anie poprzez prze- kazanie do funkcji async() strategii uruchamiania std::launch:deferred. Poni(cid:276)sza sekwencja instrukcji spowoduje odroczenie funkcji func1() do czasu wywo(cid:228)ania funkcji get() na rzecz obiektu f: 2 Strategia uruchamiania jest typem wyliczeniowym o okre(cid:264)lonym zasi(cid:246)gu, dlatego trzeba kwalifikowa(cid:232) warto(cid:264)ci (enumeratory) za pomoc(cid:241) prefiksu std::launch lub launch (patrz punkt 3.1.13). 3 Nale(cid:276)y zauwa(cid:276)y(cid:232), (cid:276)e w komitecie standaryzacyjnym by(cid:228)y kontrowersje dotycz(cid:241)ce sposobu interpretacji tych s(cid:228)ów w przypadku, gdy wynik funkcji async() nie jest u(cid:276)ywa- ny. Taki by(cid:228) rezultat dyskusji i takie powinno by(cid:232) zachowanie programu we wszystkich implementacjach. Kup książkęPoleć książkę 18.1. INTERFEJS WYSOKIEGO POZIOMU: ASYNC() I FUTURY 1009 std::future ... f(std::async(std::launch::deferred, func1)); // odroczenie funkcji func1 do czasu wywo(cid:225)ania get() W tym przypadku mamy gwarancj(cid:246), (cid:276)e funkcja func1() nie zostanie wywo(cid:228)ana bez wywo(cid:228)ania get() (lub wait()). Ta strategia umo(cid:276)liwia tzw. leniwe warto(cid:264)ciowanie (ang. lazy evaluation). Na przyk(cid:228)ad4: auto f1 = std::async( std::launch::deferred, task1 ); auto f2 = std::async( std::launch::deferred, task2 ); ... auto val = thisOrThatIsTheCase() ? f1.get() : f2.get(); Ponadto jawne (cid:276)(cid:241)danie strategii uruchamiania deferred mo(cid:276)e pomóc w zasy- mulowaniu dzia(cid:228)ania funkcji async() w (cid:264)rodowisku jednow(cid:241)tkowym. U(cid:228)atwia równie(cid:276) debugowanie (o ile nie zachodz(cid:241) warunki wy(cid:264)cigu). Obs(cid:228)uga wyj(cid:241)tków Dotychczas omawiali(cid:264)my tylko taki przypadek, kiedy w(cid:241)tki i zadania wykonywane w tle ko(cid:254)czy(cid:228)y si(cid:246) pomy(cid:264)lnie. Jednak co si(cid:246) zdarzy, kiedy wyst(cid:241)pi wyj(cid:241)tek? Dobra wiadomo(cid:264)(cid:232) jest taka, (cid:276)e nic specjalnego. Wywo(cid:228)anie funkcji get() dla futur obs(cid:228)uguje równie(cid:276) wyj(cid:241)tki. Je(cid:264)li nast(cid:241)pi wywo(cid:228)anie get(), a operacja w tle zostanie przerwana przez wyj(cid:241)tek, który nie zosta(cid:228) obs(cid:228)u(cid:276)ony wewn(cid:241)trz w(cid:241)tku, to ten wyj(cid:241)tek b(cid:246)dzie propagowany dalej. W efekcie w celu obs(cid:228)ugi wyj(cid:241)tków operacji wykonywanych w tle nale(cid:276)y post(cid:246)powa(cid:232) z funkcj(cid:241) get() w taki sam sposób, w jaki post(cid:241)piliby(cid:264)my, gdyby operacja by(cid:228)a uruchomiona synchronicznie. Na przyk(cid:228)ad spróbujmy uruchomi(cid:232) zadanie w tle z niesko(cid:254)czon(cid:241) p(cid:246)tl(cid:241) alokuj(cid:241)- c(cid:241) pami(cid:246)(cid:232) w celu wstawienia nowego elementu listy5: // concurrency/async2.cpp #include future #include list #include iostream #include exception using namespace std; void task1() { // niesko(cid:276)czone wstawianie elementu i alokacja pami(cid:266)ci // - pr(cid:266)dzej czy pó(cid:296)niej spowoduje zg(cid:225)oszenie wyj(cid:261)tku // - UWAGA: to jest z(cid:225)a praktyka list int v; while (true) { for (int i=0; i 1000000; ++i) { v.push_back(i); 4 Dzi(cid:246)kujemy Lawrence’owi Crowlowi za t(cid:246) uwag(cid:246) oraz za dostarczenie przyk(cid:228)adu. 5 Próba zu(cid:276)ywania pami(cid:246)ci do momentu, a(cid:276) wyst(cid:241)pi wyj(cid:241)tek, jest oczywi(cid:264)cie z(cid:228)(cid:241) praktyk(cid:241). W (cid:264)rodowiskach niektórych systemów operacyjnych mo(cid:276)e to spowodowa(cid:232) problemy. W zwi(cid:241)zku z tym uruchamiaj(cid:241)c ten przyk(cid:228)ad, nale(cid:276)y zachowa(cid:232) ostro(cid:276)no(cid:264)(cid:232). Kup książkęPoleć książkę 1010 18. WSPÓ(cid:224)BIE(cid:297)NO(cid:285)(cid:251) } cout.put( . ).flush(); } } int main() { cout uruchomienie 2 zada(cid:241) endl; cout - task1: przetwarzanie niesko(cid:241)czonej p(cid:218)tli zu(cid:285)ywaj(cid:200)cej pami(cid:218)(cid:202) endl; cout - task2: oczekiwanie na zwrócenie sterowania, a nast(cid:218)pnie na zako(cid:241)czenie zadania task1 endl; auto f1 = async(task1); // uruchomienie zadania task1() asynchronicznie (teraz, pó(cid:296)niej lub nigdy) cin.get(); // czytanie znaku (podobnie jak getchar()) cout oczekiwanie na zako(cid:241)czenie zadania task1: endl; try { f1.get(); // oczekiwanie na zako(cid:276)czenie zadania task1() (lub zg(cid:225)oszenie wyj(cid:261)tku) } catch (const exception e) { cerr WYJ(cid:107)TEK: e.what() endl; } } Pr(cid:246)dzej czy pó(cid:274)niej niesko(cid:254)czona p(cid:246)tla spowoduje zg(cid:228)oszenie wyj(cid:241)tku (prawdopo- dobnie b(cid:246)dzie to wyj(cid:241)tek bad_alloc — patrz punkt 4.3.1). Ten wyj(cid:241)tek spowoduje zako(cid:254)czenie w(cid:241)tku, poniewa(cid:276) nie jest nigdzie przechwycony. Ten stan b(cid:246)dzie zapi- sany w obiekcie futury do czasu wywo(cid:228)ania funkcji get(). Wywo(cid:228)anie funkcji get() spowoduje dalsz(cid:241) propagacj(cid:246) wyj(cid:241)tku wewn(cid:241)trz funkcji main(). Mo(cid:276)emy teraz podsumowa(cid:232) interfejs funkcji async() i obiektów futur w na- st(cid:246)puj(cid:241)cy sposób: funkcja async() daje (cid:264)rodowisku programistycznemu szans(cid:246) na równoleg(cid:228)e uruchomienie oblicze(cid:254), których wyniki b(cid:246)d(cid:241) wykorzystane pó(cid:274)- niej (w momencie wywo(cid:228)ania funkcji get()). Inaczej mówi(cid:241)c, je(cid:264)li mamy pewn(cid:241) niezale(cid:276)n(cid:241) funkcjonalno(cid:264)(cid:232) f, to mo(cid:276)emy skorzysta(cid:232) z równoleg(cid:228)ego przetwarza- nia, je(cid:264)li jest ono mo(cid:276)liwe, poprzez przekazanie f do funkcji async() w chwili, gdy mamy wszystko, co jest potrzebne do uruchomienia tej funkcjonalno(cid:264)ci. Na- st(cid:246)pnie w miejscu, gdzie jest potrzebny wynik funkcjonalno(cid:264)ci f, nale(cid:276)y wstawi(cid:232) wywo(cid:228)anie funkcji get() w odniesieniu do futury zwróconej przez funkcj(cid:246) async(). W ten sposób uzyskujemy ten sam wynik, ale mamy szans(cid:246) na lepsz(cid:241) wydajno(cid:264)(cid:232), poniewa(cid:276) funkcjonalno(cid:264)(cid:232) f mo(cid:276)e dzia(cid:228)a(cid:232) wspó(cid:228)bie(cid:276)nie, zanim b(cid:246)dzie potrzebny jej wynik. Oczekiwanie i odpytywanie Funkcj(cid:246) get() w odniesieniu do obiektu future mo(cid:276)na wywo(cid:228)a(cid:232) tylko raz. Po wywo(cid:228)aniu funkcji get() futura jest niewa(cid:276)na. Mo(cid:276)na to sprawdzi(cid:232) jedynie poprzez wywo(cid:228)anie funkcji valid() w odniesieniu do futury. Ka(cid:276)de wywo(cid:228)anie inne ni(cid:276) niszcz(cid:241)ce obiekt spowoduje niezdefiniowane zachowanie (szczegó(cid:228)owe informacje mo(cid:276)na znale(cid:274)(cid:232) w punkcie 18.3.2). Kup książkęPoleć książkę 18.1. INTERFEJS WYSOKIEGO POZIOMU: ASYNC() I FUTURY 1011 Futury zapewniaj(cid:241) równie(cid:276) interfejs pozwalaj(cid:241)cy na oczekiwanie na zako(cid:254)- czenie operacji dzia(cid:228)aj(cid:241)cej w tle bez przetwarzania jej wyniku. Interfejs ten mo(cid:276)e by(cid:232) wywo(cid:228)ywany wi(cid:246)cej ni(cid:276) jeden raz. Aby ograniczy(cid:232) czas oczekiwania, mo(cid:276)na do niego przekaza(cid:232) czas trwania lub punkt w czasie. Samo wywo(cid:228)anie funkcji wait() wymusza uruchomienie w(cid:241)tku reprezento- wanego przez futur(cid:246) i oczekiwanie na zako(cid:254)czenie operacji w tle: std::future ... f(std::async(func)); // próba asynchronicznego wywo(cid:225)ania funkcji ... f.wait(); // oczekiwanie na zako(cid:276)czenie funkcji (mo(cid:298)e uruchomi(cid:252) zadanie w tle) Istniej(cid:241) dwie inne odmiany funkcji wait(), które mo(cid:276)na wywo(cid:228)ywa(cid:232) w odniesieniu do futur. Funkcje te nie wymuszaj(cid:241) uruchomienia w(cid:241)tku, je(cid:264)li nie zosta(cid:228) on urucho- miony wcze(cid:264)niej: 1. Funkcja wait_for(), do której przekazujemy czas oczekiwania, pozwala czeka(cid:232) na asynchroniczne uruchomienie operacji przez ograniczony czas: std::future ... f(std::async(func)); // próba asynchronicznego wywo(cid:225)ania funkcji ... f.wait_for(std::chrono::seconds(10)); // oczekiwanie na funkcj(cid:266) func przez co najwy(cid:298)ej 10 sekund 2. Funkcja wait_until() pozwala czeka(cid:232) do okre(cid:264)lonego punktu w czasie: std::future ... f(std::async(func)); // próba asynchronicznego wywo(cid:225)ania funkcji ... f.wait_until(std::system_clock::now()+std::chrono::minutes(1)); Zarówno funkcja wait_for(), jak i wait_until() zwracaj(cid:241) jeden z poni(cid:276)szych wyników: (cid:120) std::future_status::deferred (cid:127) je(cid:264)li funkcja async() odroczy(cid:228)a operacj(cid:246) i (cid:276)adne z wywo(cid:228)a(cid:254) wait() lub get() jeszcze nie wymusi(cid:228)o jej startu (w tym przypadku obie funkcje natychmiast zwracaj(cid:241) sterowanie); (cid:120) std::future_status::timeout (cid:127) je(cid:264)li operacja zosta(cid:228)a uruchomiona asyn- chronicznie, ale jeszcze si(cid:246) nie zako(cid:254)czy(cid:228)a (je(cid:264)li oczekiwanie zako(cid:254)czy(cid:228)o si(cid:246) ze wzgl(cid:246)du na up(cid:228)yw przekazanego limitu czasu); (cid:120) std::future_status::ready (cid:127) je(cid:264)li operacja zako(cid:254)czy(cid:228)a si(cid:246). Wykorzystanie funkcji wait_for() lub wait_until() umo(cid:276)liwia tzw. spekulacyjne uruchomienie programu. Na przyk(cid:228)ad rozwa(cid:276)my scenariusz, w którym musimy uzy- ska(cid:232) wynik oblicze(cid:254) w okre(cid:264)lonym czasie i chcieliby(cid:264)my mie(cid:232) dok(cid:228)adny wynik6: int quickComputation(); // przetwarzanie wyniku szybkie i niedok(cid:225)adne int accurateComputation(); // przetwarzanie wyniku dok(cid:225)adne, ale wolne std::future int f; //zadeklarowane na zewn(cid:261)trz ze wzgl(cid:266)du na to, (cid:298)e czas (cid:298)ycia funkcji accurateComputation() // mo(cid:298)e przekroczy(cid:252) czas (cid:298)ycia funkcji bestResultInTime() int bestResultInTime() { // zdefiniowanie przedzia(cid:225)u czasowego do uzyskania odpowiedzi: auto tp = std::chrono::system_clock::now() + std::chrono::minutes(1); 6 Dzi(cid:246)kujemy Lawrence’owi Crowlowi za te informacje oraz za dostarczenie przyk(cid:228)adu. Kup książkęPoleć książkę 1012 18. WSPÓ(cid:224)BIE(cid:297)NO(cid:285)(cid:
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C++. Biblioteka standardowa. Podręcznik programisty. Wydanie II
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: