Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00054 005023 14825566 na godz. na dobę w sumie
Microsoft Visual C++ 2012. Praktyczne przykłady - książka
Microsoft Visual C++ 2012. Praktyczne przykłady - książka
Autor: Liczba stron: 384
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5352-2 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c++ - programowanie
Porównaj ceny (książka, ebook, audiobook).

Microsoft Visual C++ 2012? To nic trudnego!

Dostępne od niedawna środowisko Visual C++ 2012 oferuje użytkownikom szereg zupełnie nowych możliwości. Dzięki wprowadzeniu obsługi standardu C++11 i zwiększeniu przejrzystości oraz uniwersalności kodu źródłowego rozwiązanie ugruntowało swoją renomę nowoczesnego i nieustannie rozwijanego narzędzia programistycznego do wszechstronnych zastosowań. Ulepszone i dostosowane do nowych wymagań z powodzeniem może konkurować z innymi środowiskami obecnymi na rynku. Potwierdzają to również takie posunięcia producenta, jak zapewnienie wsparcia dla twórców programów działających w systemie Windows 8 i aplikacji mobilnych uruchamianych na platformie Windows Phone.

'Microsoft Visual C++ 2012. Praktyczne przykłady' to doskonały przewodnik dla osób chcących poznać język C++ i zacząć pisać programy w środowisku Visual C++. Książka zawiera dokładny opis składni standardowego języka C++, a także praktyczne wskazówki dotyczące tworzenia aplikacji wykorzystujących Windows API oraz .NET Framework. Podręcznik prezentuje nie tylko podstawowe konstrukcje języka i sposoby ich stosowania, lecz także wprowadza czytelnika w bardziej zaawansowane zagadnienia związane z tworzeniem aplikacji działających w systemach operacyjnych Windows. Każdy omawiany tutaj temat został zilustrowany przykładem umożliwiającym praktyczne utrwalenie poznanych wiadomości teoretycznych.

Chcesz nauczyć się szybko działać w nowym Visual C++?
Jesteś na dobrej drodze!

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

Darmowy fragment publikacji:

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 biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Redaktor prowadzący: Michał Mrowiec Projekt okładki: Studio Gravite / Olsztyn Obarek, Pokoński, Pazdrijowski, Zaprucki 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) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?vc21pp Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Kody źródłowe wybranych przykładów dostępne są pod adresem: ftp://ftp.helion.pl/przyklady/vc21pp.zip ISBN: 978-83-246-5352-2 Copyright © Helion 2013 Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treĈci Co znajdziesz w tej ksiñĔce? ............................................................. 9 Rozdziaä 1. Podstawy Ĉrodowiska Visual C++ 2012 Professional ....................... 11 Opis Ğrodowiska ............................................................................................................. 11 JĊzyk C++ a .NET Framework ....................................................................................... 12 Pobieranie i instalacja Ğrodowiska .................................................................................. 12 Kilka pojĊü na początek .................................................................................................. 14 Zmienne ................................................................................................................... 14 Funkcja ..................................................................................................................... 14 Klasy ........................................................................................................................ 15 Przestrzenie nazw ..................................................................................................... 16 Z czego skáada siĊ aplikacja Windows ........................................................................... 16 Gáówne okno VC++ 2012 RC ........................................................................................ 17 Zaginiony projekt ........................................................................................................... 18 Tworzenie projektu nowej aplikacji w VC++ 2012 ........................................................ 19 Wygląd Ğrodowiska w trybie budowy aplikacji .............................................................. 22 Struktura projektu ........................................................................................................... 24 Efektywna praca w Ğrodowisku ...................................................................................... 25 Rozdziaä 2. Struktura programów C++ i C++/CLI .............................................. 29 Programy korzystające z konsoli w VC++ 2012 ............................................................ 29 Ogólna postaü programu pisanego w C++ ...................................................................... 29 Dyrektywy ...................................................................................................................... 31 Dyrektywa #include ................................................................................................. 31 Dyrektywa #define ................................................................................................... 33 Dyrektywa #ifdef — kompilacja warunkowa ........................................................... 34 Typy zmiennych ............................................................................................................. 37 Zmienne typu int ...................................................................................................... 37 Zmienne typu float ................................................................................................... 38 Typ double ............................................................................................................... 38 Typ char ................................................................................................................... 38 Modyfikatory typów ................................................................................................. 38 Rzutowanie (konwersja) typów ...................................................................................... 39 Rzutowanie static_cast ............................................................................................. 39 Rzutowanie const_cast ............................................................................................. 40 Rzutowanie safe_cast ............................................................................................... 41 Rzutowanie dynamic_cast ........................................................................................ 41 4 Microsoft Visual C++ 2012. Praktyczne przykäady Typ wyliczeniowy .......................................................................................................... 41 Silnie typowane wyliczenia ...................................................................................... 41 Sáowo kluczowe auto, czyli dedukcja typu ..................................................................... 45 L-wartoĞci i R-wartoĞci .................................................................................................. 46 Operatory ........................................................................................................................ 46 Zapis danych do plików i odczyt z nich za pomocą operatorów i ................. 48 WskaĨniki i referencje .................................................................................................... 50 WskaĨniki ................................................................................................................. 50 Referencje ................................................................................................................ 50 Referencje do r-wartoĞci .......................................................................................... 51 WskaĨniki do staáej i rzutowanie const_cast ............................................................ 51 Tablice ............................................................................................................................ 52 Operatory new i delete .................................................................................................... 55 Instrukcje ........................................................................................................................ 55 Instrukcje warunkowe .............................................................................................. 56 Instrukcje iteracji ...................................................................................................... 57 Rozdziaä 3. Funkcje ......................................................................................... 59 Tradycyjny zapis funkcji ................................................................................................ 59 PrzeciąĪanie funkcji ........................................................................................................ 60 NiejednoznacznoĞü ................................................................................................... 60 Przekazywanie argumentów przez wartoĞü i adres ................................................... 61 WskaĨniki do funkcji, delegaty ................................................................................ 62 WyraĪenia lambda .......................................................................................................... 65 Funkcja main() ............................................................................................................... 67 Przekazywanie parametrów do funkcji main() ......................................................... 68 Szablony funkcji ............................................................................................................. 70 Rozdziaä 4. Struktury, klasy, obiekty ................................................................ 73 Struktury ......................................................................................................................... 73 Klasy ............................................................................................................................... 75 Statyczne metody i pola klasy .................................................................................. 78 WskaĨnik zwrotny this ............................................................................................. 79 Dziedziczenie ................................................................................................................. 80 Funkcje wirtualne ........................................................................................................... 83 WskaĨniki na klasy bazowe i pochodne, rzutowanie ...................................................... 85 PrzeciąĪanie operatorów ................................................................................................. 88 Szablony klas .................................................................................................................. 89 Wyjątki ........................................................................................................................... 92 Przestrzenie nazw ........................................................................................................... 94 Rozdziaä 5. Konstruowanie i usuwanie obiektów klas ........................................ 97 Konstruktory i destruktory .............................................................................................. 97 PrzeciąĪanie konstruktorów ............................................................................................ 99 Konstruktor kopiujący .................................................................................................. 100 Konstruktor przenoszący .............................................................................................. 102 Konstruktory definiowane w klasach dziedziczonych .................................................. 104 Konstruktor kopiujący w klasie potomnej .................................................................... 105 Konstruktor definiowany w szablonie klasy ................................................................. 107 Struktury a klasy — porównanie .................................................................................. 110 Rozdziaä 6. Interface win32, gäówne okno aplikacji ......................................... 113 CzĊĞci skáadowe podstawowego kodu okienkowej aplikacji win32 ............................. 113 Funkcja gáówna programu win32 ................................................................................. 115 Klasa okna gáównego .................................................................................................... 115 Spis treĈci 5 Tworzymy nowe okno .................................................................................................. 118 Procedura okna ............................................................................................................. 120 PĊtla komunikatów ....................................................................................................... 122 Zasoby ikon .................................................................................................................. 123 Zasoby menu ................................................................................................................ 128 Okna dialogowe w zasobach ........................................................................................ 131 Rozdziaä 7. Obsäuga komunikatów .................................................................. 139 Komunikaty w aplikacji Windows ............................................................................... 139 WinAPI a standard Unicode ......................................................................................... 140 Przycisk i okno tekstowe, czyli budujemy warsztat ...................................................... 140 Komunikat WM_COMMAND ..................................................................................... 142 Odmalowywanie okna — komunikat WM_PAINT ..................................................... 145 Ruch myszy sygnalizuje WM_MOUSEMOVE ............................................................ 146 WM_CREATE koĔczy tworzenie okna ........................................................................ 149 SendMessage() przeĞle kaĪdy komunikat ..................................................................... 150 Rozdziaä 8. Podstawowe kontrolki w dziaäaniu aplikacji winAPI ......................... 153 Wszechstronny przycisk Button ................................................................................... 153 Obsáuga przycisków Button jako pól wyboru ............................................................... 154 Kontrolka ComboBox ................................................................................................... 155 Rozdziaä 9. Budowa aplikacji .NET w trybie wizualnym .................................... 165 Od WinAPI do .NET Framework ................................................................................. 165 Okno w trybie wizualnym ............................................................................................ 165 Przyciski ....................................................................................................................... 171 Etykiety ........................................................................................................................ 173 Pola tekstowe ................................................................................................................ 175 Wprowadzanie danych do aplikacji za pomocą pól tekstowych ................................... 176 Wprowadzanie danych z konwersją typu ..................................................................... 178 WyĞwietlanie wartoĞci zmiennych ............................................................................... 179 Pole tekstowe z maską formatu danych ........................................................................ 180 Pola wyboru, przyciski opcji, kontenery grupujące ...................................................... 183 Rozdziaä 10. Menu i paski narzödzi .................................................................. 187 Rodzaje menu ............................................................................................................... 187 Komponent MenuStrip ................................................................................................. 187 Menu podrĊczne ........................................................................................................... 193 Skróty klawiaturowe w menu ....................................................................................... 195 Paski narzĊdzi ............................................................................................................... 197 Rozdziaä 11. Tablice, uchwyty i dynamiczne tworzenie obiektów ....................... 203 Tablice .......................................................................................................................... 203 DostĊp do elementów tablicy za pomocą enumeratora ................................................. 206 Uchwyty ....................................................................................................................... 208 Dynamiczne tworzenie obiektów — operator gcnew ................................................... 209 Dynamiczna deklaracja tablic ....................................................................................... 210 Rozdziaä 12. Komunikacja aplikacji z plikami .................................................... 213 Pliki jako Ĩródáo danych ............................................................................................... 213 Wyszukiwanie plików .................................................................................................. 214 Odczyt wáasnoĞci plików i folderów ............................................................................ 215 Odczyt danych z plików tekstowych ............................................................................ 216 Zapisywanie tekstu do pliku ......................................................................................... 220 Zapis danych do plików binarnych ............................................................................... 222 Odczyt z plików binarnych ........................................................................................... 223 6 Microsoft Visual C++ 2012. Praktyczne przykäady Rozdziaä 13. Okna dialogowe ........................................................................... 225 Okno typu MessageBox ................................................................................................ 225 Okno dialogowe otwarcia pliku .................................................................................... 227 Okno zapisu pliku ......................................................................................................... 230 Okno przeglądania folderów ......................................................................................... 231 Okno wyboru koloru ..................................................................................................... 233 Wybór czcionki ............................................................................................................ 234 Rozdziaä 14. MoĔliwoĈci edycji tekstu w komponencie TextBox ........................ 237 WáaĞciwoĞci pola TextBox ........................................................................................... 237 Kopiowanie i wklejanie tekstu ze schowka .................................................................. 239 Wyszukiwanie znaków w tekĞcie ................................................................................. 240 Wstawianie tekstu miĊdzy istniejące linie .................................................................... 241 Wprowadzanie danych do aplikacji .............................................................................. 242 Prosta konwersja typów — klasa Convert .................................................................... 242 Konwersja ze zmianą formatu danych .......................................................................... 243 Konwersja liczby na áaĔcuch znakowy ......................................................................... 246 Rozdziaä 15. Komponent tabeli DataGridView ................................................... 249 Podstawowe wáaĞciwoĞci komponentu DataGridView ................................................. 249 Zmiana wyglądu tabeli ................................................................................................. 253 Dopasowanie wymiarów komórek tabeli do wyĞwietlanego tekstu .............................. 255 Odczytywanie danych z komórek tabeli ....................................................................... 257 Zmiana liczby komórek podczas dziaáania aplikacji .................................................... 261 Tabela DataGridView z komórkami róĪnych typów .................................................... 265 Przyciski w komórkach — DataGridViewButtonCell .................................................. 268 Komórki z polami wyboru — DataGridViewCheckBoxCell ....................................... 269 Grafika w tabeli — komórka DataGridViewImageCell ............................................... 270 Komórka z listą rozwijaną — DataGridViewComboBoxCell ...................................... 272 OdnoĞniki internetowe w komórkach — DataGridViewLinkCell ................................ 274 Rozdziaä 16. Aplikacja bazy danych .................................................................. 277 Baza danych i aplikacja ................................................................................................ 277 Instalacja PostgreSQL .................................................................................................. 277 Wyáączenie usáugi bazy ................................................................................................ 281 Inicjalizacja bazy .......................................................................................................... 281 Organizacja i typy danych w bazach PostgreSQL ........................................................ 283 JĊzyk SQL .................................................................................................................... 284 Utworzenie bazy danych .............................................................................................. 285 Interfejs uĪytkownika ................................................................................................... 286 Wáączenie sterowników bazy PostgreSQL do projektu ................................................ 288 àączenie z bazą i odczyt danych ................................................................................... 290 Dodawanie danych do bazy .......................................................................................... 292 Zmiana danych w bazie ................................................................................................ 295 Kasowanie danych ........................................................................................................ 297 Obsáuga bazy ................................................................................................................ 298 Rozdziaä 17. Metody zwiñzane z czasem — komponent Timer ........................... 299 Czas systemowy ........................................................................................................... 299 Komponent Timer ........................................................................................................ 301 Rozdziaä 18. Grafika w aplikacjach .NET Framework ......................................... 303 Obiekt Graphics — kartka do rysowania ...................................................................... 303 Pióro Pen ...................................................................................................................... 308 PĊdzle zwykáe i teksturowane ....................................................................................... 310 Spis treĈci 7 Rysowanie pojedynczych punktów — obiekt Bitmap .................................................. 313 Rysowanie trwaáe — odĞwieĪanie rysunku .................................................................. 314 Animacje ...................................................................................................................... 316 Rozdziaä 19. Podstawy aplikacji wielowñtkowych ............................................. 319 Wątki ............................................................................................................................ 319 Komunikacja z komponentami z innych wątków — przekazywanie parametrów ........ 321 Przekazywanie parametrów do metody wątku .............................................................. 323 Klasa wątku — przekazywanie parametrów z kontrolą typu ........................................ 324 KoĔczenie pracy wątku ................................................................................................ 326 Semafory ...................................................................................................................... 328 Sekcje krytyczne — klasa Monitor ............................................................................... 331 Komponent BackgroundWorker ................................................................................... 334 Rozdziaä 20. Poäñczenie aplikacji z sieciñ Internet ............................................ 339 Komponent WebBrowser ............................................................................................. 339 Przetwarzanie stron Web — obiekt HtmlDocument ..................................................... 342 Uruchamianie skryptów JavaScript z poziomu aplikacji .............................................. 345 Protokóá FTP ................................................................................................................ 347 Pobieranie zawartoĞci katalogu z serwera FTP ............................................................. 348 Pobieranie plików przez FTP ........................................................................................ 350 Wysyáanie pliku na serwer FTP .................................................................................... 351 Klasa do obsáugi FTP ................................................................................................... 352 Pobieranie plików w oddzielnym wątku ....................................................................... 356 Wysyáanie plików w wątku .......................................................................................... 357 Rozdziaä 21. Dynamiczne tworzenie okien i komponentów ................................. 359 WyĞwietlanie okien — klasa Form ............................................................................... 359 Komponenty w oknie tworzonym dynamicznie ........................................................... 361 Przesyáanie danych z okien dialogowych ..................................................................... 362 Okno tytuáowe aplikacji ................................................................................................ 363 Obsáuga zdarzeĔ dla komponentów tworzonych dynamicznie ..................................... 364 Aplikacja zabezpieczona hasáem .................................................................................. 365 Rozdziaä 22. Prosty manager plików ................................................................. 367 Interfejs managera ........................................................................................................ 367 WyĞwietlanie zawartoĞci folderów ............................................................................... 367 Formatowanie prezentacji folderu .......................................................................... 369 Przechodzenie w dóá i w górĊ drzewa plików ............................................................... 372 Idziemy w górĊ ....................................................................................................... 372 Idziemy w dóá ......................................................................................................... 373 Kopiowanie plików miĊdzy panelami .......................................................................... 374 Kasowanie plików ........................................................................................................ 375 Skorowidz .................................................................................... 377 8 Microsoft Visual C++ 2012. Praktyczne przykäady Rozdziaä 19. Podstawy aplikacji wielowñtkowych Wñtki W systemach wielowątkowych wiele programów moĪe byü wykonywanych jednocze- Ğnie. W systemach jednoprocesorowych wraĪenie jednoczesnoĞci wykonania powstaje dziĊki przydzielaniu czasu procesora dla kolejnych programów na przemian. KaĪdy z takich wykonywanych równolegle algorytmów nosi nazwĊ wątku. Znaczenie aplikacji wielowątkowych wzrosáo po pojawieniu siĊ procesorów z kilkoma rdzeniami. DziĊki takiej architekturze moĪliwa jest rzeczywista jednoczesnoĞü wykonywania wątków. Standardowo aplikacja skáada siĊ tylko z jednego wątku, związanego z oknem gáównym. Taki model nie zawsze jest wystarczający. PoniewaĪ podczas wykonywania kodu metody nie są przetwarzane zdarzenia dla danego wątku, w przypadku dáuĪszych metod okno aplikacji nie jest odĞwieĪane i nie jest moĪliwa obsáuga kontrolek. Z tego powo- du okno aplikacji wydaje siĊ „zablokowane” i nie jest moĪliwe wyĞwietlanie Īadnych danych na przykáad w kontrolce etykiety Label. Aby poprawiü dziaáanie takiej aplikacji, naleĪy wykonywaü czĊĞü kodu jako oddzielny wątek. Wątek jest reprezentowany w aplikacji przez obiekt klasy Thread. Przy tworzeniu tego obiektu parametrem konstruktora jest metoda, która bĊdzie wykonywana w tym wątku. NastĊpnie do rozpoczĊcia wątku sáuĪy metoda Start() klasy Thread, którą wy- konujemy na utworzonym obiekcie. PrzeĞledzimy zastosowanie oddzielnych wątków na przykáadzie programu wymagającego dáugich obliczeĔ. Przykäad 19.1 Napisz program odnajdujący liczby pierwsze w przedziale od 2 do 100 000. Liczba pierwsza to taka, która dzieli siĊ tylko przez 1 i przez samą siebie. 320 Microsoft Visual C++ 2012. Praktyczne przykäady Rozwiązanie Najpierw napiszemy tĊ aplikacjĊ jako klasyczną aplikacjĊ z pojedynczym wątkiem. Utwórz nowy projekt wedáug przykáadu 1.4 i wstaw do formatki przycisk Button oraz pole tekstowe TextBox. WáaĞciwoĞü Multiline pola ustaw na true i zwiĊksz wymiary pola tak, aby zmieĞciáo kilka linii. Zdarzenie Click przycisku bĊdzie uruchamiaáo metodĊ po- szukującą liczb pierwszych. W tym przypadku zastosujemy prosty algorytm, który dzieli modulo kolejne liczby i przez liczby od 2 do i, sprawdzając w ten sposób, czy liczba i ma podzielnik inny niĪ ona sama. W momencie znalezienia dzielnika koĔczy siĊ pĊtla while. JeĪeli dzielnikiem dla danej liczby jest ona sama, to liczba jest wyĞwie- tlana. Nie jest to najbardziej efektywny algorytm, ale nie o to tu chodzi. private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { System::Int32 n=2; for (System::Int32 i=2;i 100000;i++) { n=2; while ((i n)) n++; if (i==n) textBox1- AppendText(i.ToString()+System::Environment::NewLine); } } Po uruchomieniu obliczeĔ przyciskiem program wydaje siĊ dziaáaü normalnie, jednak próba przesuniĊcia okna programu nie powiedzie siĊ, a w przypadku zasáoniĊcia okna przez inną aplikacjĊ i powtórnego odsáoniĊcia okno bĊdzie puste, dopóki nie skoĔczą siĊ obliczenia. Przykäad 19.2 Napisz program identyczny jak w przykáadzie 19.1, ale z uruchamianiem obliczeĔ w oddzielnym wątku. Rozwiązanie Utwórz nowy projekt aplikacji wedáug przykáadu 1.4 i wstaw do okna przycisk Button i pole tekstowe TextBox. RównieĪ tu ustaw wáaĞciwoĞü Multiline pola TextBox na true. Na początku kodu w pliku Form1.h obok dyrektyw zaáączania przestrzeni nazw using namespace doáącz do programu przestrzeĔ nazw z metodami wielowątkowoĞci. using namespace System::Threading; Teraz utwórz metodĊ, która bĊdzie siĊ uruchamiaáa w wątku jako metoda klasy Form1. Metoda bĊdzie poszukiwaáa liczb pierwszych tak samo jak poprzednio. Zadeklaruj ją po dyrektywie #pragma endregion. private: System::Void watek() { System::Int32 n=2; for (System::Int32 i=2;i 100000;i++) { n=2; Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 321 while ((i n)) n++; } } NaciĞniĊcie przycisku utworzy i uruchomi wątek. private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ watek_liczenia = gcnew Thread(gcnew ThreadStart(this, Form1::watek)); watek_liczenia- Start(); } Argumentem konstruktora obiektu Thread jest metoda wątku. Nie podstawiamy jej bezpoĞrednio, ale uĪywamy delegata ThreadStart. O delegatach pisaáem w rozdziale o funkcjach. Tak samo jak tam konstrukcjĊ tego obiektu umieĞciáem bezpoĞrednio na liĞcie parametrów konstruktora obiektu Thread. Parametrami obiektu ThreadStart są: obiekt klasy, do której naleĪy metoda wątku (w tym przypadku jest to klasa gáównego okna aplikacji pobierana za pomocą wskaĨnika this), oraz referencja do metody wątku. Referencja musi zawieraü nazwĊ klasy, do której naleĪy metoda wątku, i nazwĊ samej metody wątku. Po uruchomieniu programu i naciĞniĊciu przycisku program rozpoczyna obliczenia, ale nic nie wyĞwietla. MoĪna sprawdziü, Īe program liczy, wywoáując MenedĪera zadaĔ. Po naciĞniĊciu przycisku roĞnie stopieĔ wykorzystania procesora przez naszą aplikacjĊ. Mimo Īe aplikacja liczy, moĪna ją swobodnie przesuwaü, a po zakryciu i odkryciu okno ma normalny wygląd. Zapisz aplikacjĊ, dokoĔczymy ją w nastĊpnym przykáadzie. To, Īe program z poprzedniego przykáadu nic nie wyĞwietla, nie wynika z zapomnie- nia, ale wymaga oddzielnego omówienia. W aplikacji wielowątkowej moĪna korzystaü z komponentów wizualnych naleĪących do tego samego wątku. PoniewaĪ pole tekstowe TextBox jest w innym wątku niĪ obliczenia, nie jest moĪliwe korzystanie z niego bezpo- Ğrednio. Dzieje siĊ tak dlatego, Īe mógáby wtedy wystąpiü konflikt miĊdzy komuni- katami przesyáanymi do kontrolek z róĪnych wątków. NastĊpny przykáad pokazuje, jak poradziü sobie z tym ograniczeniem. Komunikacja z komponentami z innych wñtków — przekazywanie parametrów PoniewaĪ niemoĪliwa jest komunikacja z kontrolkami pochodzącymi z innego wątku, kaĪde odwoáanie do komponentu musi byü realizowane z wątku, do którego naleĪy komponent. Wiele komponentów posiada metodĊ Invoke(), która wywoáuje dowolną inną metodĊ (za pomocą delegata) tak, jakby byáa ona wywoáywana w wątku, do które- go naleĪy kontrolka. KomunikacjĊ z komponentami z innych wątków moĪna zapisaü w punktach: 322 Microsoft Visual C++ 2012. Praktyczne przykäady a) W klasie okna, do której naleĪy kontrolka okna, definiujemy metodĊ komunikującą siĊ z tą kontrolką (na przykáad piszącą do pola tekstowego). b) RównieĪ w klasie okna, do którego naleĪy kontrolka, deklarujemy delegat ze sáowem kluczowym delegate (podobnie do deklaracji zmiennej lub pola klasy). c) W metodzie wątku (która teĪ jest metodą klasy tego okna) definiujemy delegat metody, przy czym jako argument konstruktora podajemy metodĊ zdefiniowaną w punkcie a). d) Kiedy potrzebne jest odwoáanie do kontrolki w wątku, uĪywamy metody Invoke() ze zdefiniowanym w punkcie c) delegatem jako parametrem. MyĞlĊ, Īe wiele wyjaĞni nastĊpny przykáad. Przykäad 19.3 Popraw aplikacjĊ tak, aby wyĞwietlaáa znalezione liczby pierwsze. Rozwiązanie Otwórz aplikacjĊ z poprzedniego przykáadu. Caáa trudnoĞü tego przykáadu polega na tym, Īe metoda poszukiwania liczb pierwszych uruchamiana w oddzielnym wątku bĊdzie musiaáa pisaü liczby do okna tekstowego znajdującego siĊ w wątku okna gáównego. Najpierw w klasie Form1 napisz metodĊ, która bĊdzie wpisywaáa podaną jako argument liczbĊ do pola tekstowego. private: System::Void wyswietl(System::Int32 i) { textBox1- AppendText(i.ToString()+System::Environment::NewLine); } Teraz równieĪ w klasie Form1 utwórz deklaracjĊ delegata — tak jak zwykáej metody klasy, ale ze sáowem kluczowym delegate. Delegat musi mieü listĊ parametrów taką jak metoda, która bĊdzie posáugiwaáa siĊ komponentem z innego wątku (czyli u nas metoda wyswietl()). private:delegate void wyswDelegat(System::Int32 i); W metodzie wątku watek() trzeba zdefiniowaü wystąpienie delegata. Konstruktor delegata ma dwa parametry: pierwszy to klasa, z której pochodzi metoda odwoáująca siĊ do kontrolki, a drugi to wskaĨnik do samej metody. Po stworzeniu obiektu delegata w celu pisania do pola tekstowego wywoáujemy metodĊ Invoke(). Pierwszy parametr tej metody to obiekt delegata, a drugi to tabela obiektów typu obiekt zawierająca wartoĞci parametrów metody. W naszym przypadku metoda wyswietl() ma tylko jeden para- metr. Oto poprawiony kod metody watek(): private: System::Void watek() { wyswDelegat^ wyswietlDelegat = gcnew wyswDelegat(this, Form1::wyswietl); System::Int32 n=2; Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 323 for (System::Int32 i=2;i 100000;i++) { n=2; while ((i n)) n++; if (i==n) this- Invoke(wyswietlDelegat, gcnew array System::Object^ (1){i}); } } MoĪna juĪ uruchomiü program. Po naciĞniĊciu przycisku liczby pojawiają siĊ w polu, a okno daje siĊ swobodnie przesuwaü i zakrywaü. JeĞli zakoĔczysz dziaáanie aplikacji przyciskiem w prawym górnym rogu, zobaczysz komunikat o báĊdzie: Additional information: Cannot access a disposed object. Pojawia siĊ on dlatego, Īe zamykamy gáówne okno aplikacji, a wątek nadal istnieje i pró- buje napisaü coĞ w kontrolce TextBox, która juĪ nie istnieje. Jak temu zaradziü, napiszĊ w dalszej czĊĞci rozdziaáu. Zapisz program, poniewaĪ bĊdzie przydatny w nastĊpnym przykáadzie. Przekazywanie parametrów do metody wñtku Do tej pory metoda wątku byáa bezparametrowa, czasem jednak konieczne jest przeka- zanie parametrów. Wtedy przy tworzeniu obiektu klasy Thread posáugujemy siĊ delegatem ParameterizedThreadStart zamiast ThreadStart. WartoĞü parametru przekazujemy w metodzie Start() przy uruchamianiu wątku. Przykäad 19.4 W aplikacji poszukującej liczb pierwszych przekazuj górną granicĊ poszukiwania liczb do metody wątku za pomocą parametru. Rozwiązanie Otwórz aplikacjĊ z poprzedniego przykáadu. Dodaj pole tekstowe, w które bĊdziemy wprowadzaü górną granicĊ poszukiwaĔ. MetodĊ wątku zmodyfikuj jak niĪej. Parametr przekazywany do metody musi byü typu Object, dlatego przy podstawianiu do pĊtli for wykonujemy konwersjĊ. private: System::Void watek(Object^ i_max) { wyswDelegat^ wyswietlDelegat = gcnew wyswDelegat(this, Form1::wyswietl); 324 Microsoft Visual C++ 2012. Praktyczne przykäady System::Int32 n=2; for (System::Int32 i=2;i Convert::ToInt32(i_max);i++) { n=2; while ((i n)) n++; if (i==n) this- Invoke(wyswietlDelegat,gcnew array System::Object^ (1){i}); } } Metoda obsáugująca zdarzenie Click bĊdzie teraz korzystaáa z delegata Parameterized- ThreadStart i metody Start() z argumentem pobranym z drugiego pola tekstowego. private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ watek_liczenia = gcnew Thread(gcnew ParameterizedThreadStart(this, Form1::watek)); watek_liczenia- Start(textBox2- Text); } Po uruchomieniu programu wpisz liczbĊ caákowitą w drugie pole tekstowe i naciĞnij przycisk. Zostaną wygenerowane tylko liczby mniejsze do zadanej. Wygląd aplikacji przedstawia rysunek 19.1. Rysunek 19.1. Aplikacja wyszukująca liczby pierwsze Niestety, ten sposób przekazywania parametrów ma wady. Po pierwsze, moĪna przeka- zaü tylko jeden parametr (moĪna przekazaü tablicĊ, ale nie zawsze jest to wygodne), a na dodatek musi byü on typu Object. Jest to bardzo pierwotny typ i akceptuje wiĊkszoĞü typów standardowych, co powoduje, Īe nie ma kontroli nad przekazywanymi danymi i áatwo popeániü báąd, który nie zostanie zauwaĪony. Klasa wñtku — przekazywanie parametrów z kontrolñ typu Aby pozbyü siĊ powyĪszych problemów z typami danych, moĪna zapisaü metodĊ wątku jako metodĊ oddzielnej klasy, a parametry jako zmienne tej klasy. Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 325 Przykäad 19.5 Zapisz metodĊ wątku jako metodĊ klasy. Rozwiązanie Utwórz nowy projekt aplikacji okienkowej C++/CLI i wstaw do niego dwa pola teksto- we oraz przycisk. Pole tekstowe textBox1 bĊdzie sáuĪyáo do wyĞwietlania liczb, a textBox2 do wprowa- dzania górnej granicy poszukiwaĔ. WáaĞciwoĞü Multiline pola textBox1 ustaw na true i powiĊksz je, aby mieĞciáo kilka linii tekstu. Nie zapomnij o zaáączeniu przestrzeni nazw dla wielowątkowoĞci. using namespace System::Threading; Zacznij od napisania klasy wątku, którą nazwiemy SzukLiczbPierw. Oprócz metody liczącej wątku klasa bĊdzie zawieraü konstruktor inicjalizujący zmienne klasy poda- nymi wartoĞciami. WartoĞci te nie są juĪ typu Object, ale mają konkretne typy. Z tych zmiennych bĊdzie korzystaü metoda wątku. Jedną ze zmiennych klasy jest uchwyt do pola tekstowego, do którego bĊdą wpisywane liczby. Metoda wpisująca liczby do pola równieĪ jest czĊĞcią klasy wątku. Wywoáanie tej metody poprzez metodĊ Invoke() po- woduje, Īe jest ona wywoáywana jako metoda wątku, w którym znajduje siĊ pole tek- stowe. ZauwaĪ, Īe teraz metoda Invoke() nie jest wywoáywana na oknie aplikacji, ale na obiekcie pola tekstowego. KlasĊ umieĞü przed klasą Form1, zaraz po dyrektywach using namespace. public ref class SzukLiczbPierw { private: System::Int32 i_max; private: TextBox^ pole; private:delegate void wyswDelegat1(System::Int32 i); private: System::Void wyswietl1(System::Int32 i) { pole- AppendText(i.ToString()+System::Environment::NewLine); } // konstruktor public: SzukLiczbPierw (System::Int32 gora,TextBox^ ramka) { i_max=gora; pole=ramka; } // metoda obliczeĔ public: System::Void watek1() { wyswDelegat1^ wyswietlDelegat = gcnew wyswDelegat1(this, SzukLiczbPierw::wyswietl1); System::Int32 n=2; for (System::Int32 i=2;i Convert::ToInt32(i_max);i++) { n=2; while ((i n)) n++; if (i==n) pole- Invoke(wyswietlDelegat,gcnew array ´ System::Object^ (1){i}); } } }; 326 Microsoft Visual C++ 2012. Praktyczne przykäady Teraz trzeba zaprogramowaü metodĊ dla zdarzenia Click przycisku. W tej metodzie bĊdzie tworzony obiekt klasy wątku, a nastĊpnie sam wątek. Parametry do metody wątku przekazujemy poprzez konstruktor klasy wątku. PoniewaĪ metoda licząca jest teraz metodą klasy SzukLiczbPierw, a nie klasy Form1, parametry delegata tej metody to nie wskaĨnik this, ale obiekt klasy SzukLiczbPierw. Drugim parametrem jest referencja do metody obliczającej. private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { SzukLiczbPierw^ obliczenia = gcnew SzukLiczbPierw(Convert::ToInt32(textBox2- Text),textBox1); Thread^ watek_liczenia = gcnew Thread(gcnew ThreadStart(obliczenia, SzukLiczbPierw::watek1)); watek_liczenia- Start(); } Program po uruchomieniu bĊdzie dziaáaá identycznie jak program z poprzedniego przykáadu. Tryb graficznego projektowania okna aplikacji wymaga, aby klasa Form1 byäa pierw- szñ w pliku Form1.h. JeĔeli umieĈcisz na poczñtku innñ klasö, stracisz moĔliwoĈè wizualnego projektowania aplikacji. Dlatego wszystkie kontrolki naleĔy umieĈciè przed napisaniem klasy wñtku. TakĔe metodö obsäugujñcñ zdarzenia trzeba utworzyè przed umieszczeniem klasy wñtku. Koþczenie pracy wñtku Przed zakoĔczeniem dziaáania aplikacji powinna ona zamknąü wszystkie wątki, które do niej naleĪą. Inaczej wystĊpuje báąd, z którym siĊ juĪ zetknąáeĞ. MoĪe on prowadziü do tzw. wycieków pamiĊci i na pewno nie zwiĊksza bezpieczeĔstwa aplikacji. Wątek zakoĔczy pracĊ w normalnym trybie, jeĞli powrócimy z jego funkcji za pomo- cą instrukcji return. Eleganckie zakoĔczenie wątku moĪe wiĊc wyglądaü tak: 1. Deklarujemy zmienną globalną typu bool. 2. W metodzie wątku okresowo sprawdzamy, czy ta zmienna ma wartoĞü np. true. JeĞli tak, to wychodzimy z wątku za pomocą return. 3. W wątku okna gáównego wystarczy zmieniü w dowolnym momencie wartoĞü tej zmiennej na true i wątek siĊ zakoĔczy. ZakoĔczenie wątku nie bĊdzie natychmiastowe, ale upáynie pewien czas, zanim wątek sprawdzi wartoĞü zmiennej. JeĞli koĔczymy wątek przyciskiem, to nie ma problemu, czas ten bĊdzie niezauwaĪalny. Gorzej, jeĞli koĔczymy wątek z powodu tego, Īe zamy- kamy okno aplikacji. Wtedy od ustawienia zmiennej kontrolnej moĪe upáynąü za maáo czasu i wątek siĊ nie zakoĔczy. Jest kilka sposobów na rozwiązanie tego problemu. NajproĞciej wstrzymaü w jakiĞ sposób zamykanie aplikacji, aĪ wątek siĊ zakoĔczy. Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 327 Ja zastosujĊ sposób chyba najprostszy i moĪe maáo efektowny, ale skuteczny. Przy za- koĔczeniu aplikacji odwrócimy uwagĊ uĪytkownika, wyĞwietlając okno dialogowe i prosząc o zatwierdzenie przyciskiem OK. Zanim uĪytkownik zatwierdzi okno, wątek juĪ siĊ zakoĔczy. Przykäad 19.6 Biorąc za punkt wyjĞcia aplikacjĊ z przykáadu 19.3, zadbaj o zakoĔczenie wątku. Rozwiązanie Wykonaj jeszcze raz przykáad 19.3, jeĞli nie masz tego programu. Dodaj aplikacji drugi przycisk Button. We wáaĞciwoĞci Text tego przycisku wpisz Stop, bĊdzie on zatrzymy- waá wątek. Po dyrektywie #pragma endregion zadeklaruj zmienną sterującą. private: bool koniec_watku; Do metody watek w gáównej jej pĊtli dodamy okresowe sprawdzenie wartoĞci zmiennej. ZnajdĨ w metodzie poniĪszą liniĊ i dopisz nastĊpną: for (System::Int32 i=2;i 100000;i++) { // ta linia istnieje if (koniec_watku==true) return; } Teraz kliknij podwójnie przycisk Stop i uzupeánij powstaáą funkcjĊ jak niĪej: private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { koniec_watku=true; } W powyĪszej funkcji zmieniamy wartoĞü zmiennej sterującej, powodując, Īe warunek zakoĔczenia wątku bĊdzie speániony. Teraz to samo trzeba zrobiü, kiedy okno bĊdzie zamykane. Wykorzystamy do tego zdarzenie FormClosing. Kliknij okno aplikacji w widoku projektowania. RozwiĔ panel Properties, przeáącz siĊ na widok zdarzeĔ, znajdĨ FormClosing i kliknij dwukrotnie. Utworzy siĊ funkcja obsáugująca to zdarzenie. W tej funkcji umieĞcimy ustawienie zmiennej koniec_watku na true, ale to nie daje pewnoĞci, Īe wątek zakoĔczy siĊ przed zakoĔczeniem programu. Wobec tego, aby zyskaü na czasie, wyĞwietlimy okno Message- Box, które juĪ znasz. Oto caáa funkcja: private: System::Void Form1_FormClosing(System::Object^ sender, System::Windows:: ´Forms::FormClosingEventArgs^ e) { koniec_watku=true; MessageBox::Show(L Zatrzymuje wÈtki liczenia , Zaczekaj , ´MessageBoxButtons::OK); } Uruchom aplikacjĊ, kliknij przycisk uruchamiający wątek, a nastĊpnie, nie czekając na koniec obliczeĔ, spróbuj zamknąü okno przyciskiem X w pasku. 328 Microsoft Visual C++ 2012. Praktyczne przykäady Pojawi siĊ okno dialogowe, a w oknie Output na dole Ğrodowiska zobaczysz taki ko- munikat: The thread No Name (0xa98) has exited with code 0 (0x0). Oznacza to, Īe wątek zakoĔczyá siĊ bezpiecznie. KlikniĊcie OK zakoĔczy dziaáanie caáej aplikacji. Semafory Pomimo tytuáu dalszy ciąg ksiąĪki to nie podrĊcznik kolejnictwa — zostajemy przy programowaniu. Nazwa jest jak najbardziej trafiona. Semafory to obiekty, które prze- puszczają okreĞloną liczbĊ wątków. Stan semafora opisywany jest przez liczbĊ. Jest to liczba wątków, jaka moĪe byü wpuszczona. Wątek poprzez wywoáanie okreĞlonej metody zapytuje semafor, czy jest dla niego miejsce. JeĞli tak, to wartoĞü jest obniĪana o jeden, a wątek moĪe kontynuowaü dziaáanie. JeĞli wartoĞü wynosi zero, to wątek jest zawieszany. Proces, który zostaá wpuszczony, wychodząc z obszaru dziaáania semafora, wywoáuje inną metodĊ, która podnosi wartoĞü semafora. Wtedy inny czekający wątek moĪe zostaü odblokowany, a wartoĞü jest obniĪana. W praktyce mamy klasĊ Semaphore i dwie metody: WaitOne() i Relase(). Tworzymy obiekt Semaphore, nastĊpnie w metodzie wątku wywoáujemy na nim WaitOne(). Od tego momentu albo wątek jest „wpuszczany” przez semafor i wykonuje siĊ dalej, albo jego wykonanie jest zawieszane, aĪ semafor bĊdzie akceptowaá nowe wątki. JeĞli wątek chce zwolniü semafor, wywoáa na nim me- todĊ Relase(). Powoduje to podwyĪszenie wartoĞci semafora, który moĪe wpuĞciü nastĊpny wątek. Zwolnienie semafora nie musi oznaczaü koĔca wątku, który go opuszcza. MoĪe on nadal dziaü, ale nie ma juĪ związku z semaforem. Konstruktorów samego obiektu Semaphore jest kilka. Ja uĪyjĊ formy, która akceptuje dwie liczby. Pierwsza to początkowa wartoĞü semafora, czyli liczba wątków, które moĪe przepuĞciü zaraz po utworzeniu. Druga liczba to jego maksymalna dopuszczalna wartoĞü. Przykäad 19.7 Napisz program, w którym kolejne wątki uruchamia siĊ za pomocą przycisku. Po rozpo- czĊciu dziaáania wątki bĊdą pytaü o wpuszczenie przez semafor. Niech semafor w aplikacji przepuszcza maksymalnie trzy wątki. Rozwiązanie Utwórz nowy projekt aplikacji okienkowej C++/CLI wedáug przykáadu 1.4. Do okna wstaw dwa okna TextBox i przycisk Button. Jedno pole tekstowe bĊdzie pokazywaáo komunikaty wątków poza semaforem, a drugie wątków przepuszczonych. W bloku dy- rektyw using namespace doáącz przestrzeĔ nazw System::Threading. using namespace System::Threading; Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 329 Aby wątki mogáy pisaü w polach tekstowych, trzeba skorzystaü z delegata metody piszą- cej do pola tekstowego, tak jak w przykáadzie 19.3. Tym razem mamy dwa pola i napi- szemy dwie metody. Wpisz je po dyrektywie #pragma endregion. private: System::Void wyswietl1(System::String^ st) { textBox1- AppendText(st); } private: System::Void wyswietl2(System::String^ st) { textBox2- AppendText(st); } Zaraz niĪej zadeklaruj delegata metody o liĞcie parametrów takiej jak wyswietl1() i wyswietl2(). private: delegate void wyswDelegat(System::String^ st); Wreszcie czas na samą metodĊ wątku. Tak jak w przykáadzie 19.3 mamy deklaracjĊ obiektów delegata. NastĊpnie wątek melduje siĊ w pierwszym oknie i zapytuje o wpuszczenie przez semafor. JeĞli zostanie wpuszczony, to symuluje swoją pracĊ przez 3-sekundowy „sen”, a nastĊpnie zwalnia semafor metodą Relase(). Od razu wyĞwietla wartoĞü zwróconą z metody — jest to stan semafora przed jej wywoáaniem. Aktualny stan bĊdzie o jeden wiĊkszy, bo stan to liczba wątków, które mogą byü przepuszczone. Oto caáa metoda wątku: private: System::Void watek(System::Object^ num) { wyswDelegat^ wyswietlDelegat1 = gcnew wyswDelegat(this, Form1::wyswietl1); wyswDelegat^ wyswietlDelegat2 = gcnew wyswDelegat(this, Form1::wyswietl2); this- Invoke(wyswietlDelegat1, safe_cast System::Object^ (L WÈtek +num- ToString()+ czeka pod semaforem. +System::Environment::NewLine) ); //zapytanie o stan semafora semafor- WaitOne(); this- Invoke(wyswietlDelegat2, safe_cast System::Object^ (L WÈtek +num- ToString()+ przekroczyï semafor. +System::Environment::NewLine)); Thread::Sleep(3000); this- Invoke(wyswietlDelegat2, safe_cast System::Object^ (L WÈtek +num- ToString()+ zwolniï semafor. +System::Environment::NewLine)); //zwolnienie semafora this- Invoke(wyswietlDelegat2, safe_cast System::Object^ (L Aktulany stan ´semafora: +(semafor- Release()+1).ToString()+System:: ´Environment::NewLine)); } Trzeba jeszcze zadeklarowaü uchwyt do obiektu semafora. MoĪesz to zrobiü zaraz po metodach wyswietl1() i wyswietl2(). private: Semaphore^ semafor; Zaraz pod nim zadeklaruj zmienną, która przyda siĊ przy numeracji wątków. private: System::Int32 i; 330 Microsoft Visual C++ 2012. Praktyczne przykäady Na początku wykonywania aplikacji utworzymy obiekt semafora i ustawimy wartoĞü zmiennej pomocniczej. Dobrze do tego celu nadaje siĊ zdarzenie Load okna aplikacji. Kliknij na to okno w widoku projektowania. WaĪne, aby kliknąü na samo okno, a nie na którąĞ z kontrolek. Utworzy siĊ metoda obsáugi zdarzenia Load. W tej metodzie wy- woáamy konstruktor semafora. Parametry oznaczają, Īe na początku semafor ma war- toĞü 3 i jest to zarazem maksymalna jego wartoĞü. Zmienna i ma wartoĞü jeden i jest to numer pierwszego wątku. private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { semafor = gcnew Semaphore(3, 3); i=1; } Pozostaáa metoda klikniĊcia przycisku. Kliknij go dwukrotnie w widoku projektowania aplikacji. WnĊtrze bĊdzie raczej proste: tworzymy nowy wątek, uruchamiamy go, prze- kazując jako parametr jego numer, i zwiĊkszamy numer o jeden dla nastĊpnego wątku. private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ t = gcnew Thread(gcnew ParameterizedThreadStart(this, Form1::watek)); t- Start(i); i++; } Uruchom aplikacjĊ. Kliknij 4 razy w miarĊ szybko na przycisk. Chodzi o to, Īeby uruchomiü cztery wątki w ciągu mniej niĪ trzech sekund. Wynik dziaáania mamy na rysunku 9.2. Rysunek 9.2. Dziaáanie aplikacji z semaforem Wątki 1, 2 i 3 zostaáy wpuszczone prawie bez czekania, a wątek 4 czeka. Stan semafora wynosi w tej chwili zero. Kiedy wątek 1 zwalnia semafor, jego stan zmienia siĊ na 1 i zo- staje wpuszczony wątek 4. Po pracy wszystkie wątki zwiĊkszają stan semafora. Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 331 Sekcje krytyczne — klasa Monitor Niektóre czĊĞci kodu aplikacji nie powinny byü dostĊpne jednoczeĞnie dla wiĊcej niĪ jednego wątku. MoĪna to zrealizowaü za pomocą semafora o początkowej wartoĞci równej jeden. Innym sposobem jest uĪycie specjalnej klasy .NET Framework o nazwie Monitor. W prostym przypadku waĪne bĊdą dla nas dwie metody statyczne tej klasy: Enter() i Exit(). Metoda Enter() oznacza początek sekcji krytycznej, a Exit() koniec. Parametrem tych metod jest obiekt, który chcemy udostĊpniü tylko danemu wątkowi. ZaáóĪmy, Īe mamy obiekt o nazwie okno, na którym bĊdzie operowaá jakiĞ wątek; moĪe to byü dowolna operacja, na przykáad zmiana koloru okna. W metodzie wątku piszemy: Monitor:: Enter(okno); Od teraz tylko ten wątek ma dostĊp do okna. KaĪdy inny wątek, który spróbuje siĊ po- woáaü na obiekt okno, zostanie zawieszony. Teraz zmieniamy kolor okna: Okno- Frenolog=Blue; i sygnalizujemy, Īe juĪ nie chcemy mieü wyáącznoĞci na dostĊp: Monitor::Exit(okno); To caáa filozofia sekcji krytycznych z klasą Monitor. OczywiĞcie, jak to czĊsto bywa, problemem są szczegóáy. JeĞli wątek zapĊtli siĊ w sekcji krytycznej, to moĪe nigdy nie zawoáaü metody Exit() i zablokowaü dostĊp do okna na staáe. Dlatego korzystamy z obsáugi wyjątków. Instrukcje sekcji krytycznej umieszczamy w bloku try, a metodĊ Exit() umieszczamy w czĊĞci finally tego bloku. Kod z bloku finally zostanie wyko- nany zawsze, niezaleĪnie od tego, czy blok try wyrzuci jakiĞ wyjątek, czy nie. Przy- káad sekcji krytycznej bĊdzie ostatecznie wyglądaá tak: Monitor::Enter(okno); try { Okno- ForeColor=Blue;} finally { Monitor::Exit(okno);} Jako przykáad pokaĪĊ róĪnicĊ w dostĊpie do okna bez sekcji krytycznej i z zabezpie- czeniem sekcją. Przykäad 19.8 Niech trzy wątki starają siĊ równoczeĞnie pisaü do kontrolki TextBox w oknie aplikacji. DostĊp do okna w jednym wariancie bĊdzie nielimitowany, a w drugim zabezpieczony sekcją krytyczną. Rozwiązanie Utwórz nowy projekt aplikacji okienkowej wedáug przykáadu 1.4. Wstaw do okna pole tekstowe TextBox i przycisk Button. WáaĞciwoĞü Multiline kontrolki TextBox ustaw na true i zwiĊksz jej wymiary tak, aby mogáa pomieĞciü kilka linii. Tak samo jak w po- przednim przykáadzie bĊdziemy potrzebowaü przestrzeni nazw System::Threading. Doáącz ją w bloku using namespace. 332 Microsoft Visual C++ 2012. Praktyczne przykäady using namespace System::Drawing; //ta linia istnieje using namespace System::Threading; Aby metoda wątku mogáa pisaü do pola tekstowego, potrzebna jest metoda pisząca i delegat, tak jak to robiliĞmy juĪ wielokrotnie. Zasada sekcji krytycznej bĊdzie lepiej widoczna, jeĞli wszystkie napisy z wątków bĊdą w jednej linii. Wprowadzimy uchwyt do zmiennej System::String tekst. Wątki bĊdą dopisywaü wyniki swojego dziaáania do tej zmiennej i bĊdzie ona wyĞwietlana w polu tekstowym. PoniĪszy kod wpisz po #pragma endregion: #pragma endregion //ta linia istnieje private: static System::String^ tekst; private: System::Void wyswietl1(System::String^ st) { tekst=tekst+ +st; textBox1- AppendText(tekst+System::Environment::NewLine); } private: delegate void wyswDelegat(System::String^ st); Metoda wątku bĊdzie miaáa dwa warianty, które bĊdziemy uruchamiaü kolejno. W kaĪ- dym wariancie dziaáanie wątku bĊdzie polegaáo na wypisaniu liczb od 1 do 5, tyle Īe raz bĊdzie to realizowane bez Īadnych ograniczeĔ, a raz z zamkniĊciem dostĊpu do okna dla innych wątków. Kod wariantu, którego nie chcemy uruchamiaü, oznaczymy jako komentarz. Oto caáa metoda wątku: private: System::Void watek(Object^ nr) { wyswDelegat^ wyswietlDelegat1 = gcnew wyswDelegat(this, Form1::wyswietl1); //wariant 1 bez kontroli for (System::Int32 j=1;j 5;j++) this- Invoke(wyswietlDelegat1, safe_cast System::Object^ ´(nr+ _ +j.ToString()+ , )); //wariant 2 sekcja krytyczna /* Monitor::Enter(this); //blokada dostĊpu do caáej klasy Form1 try { for (System::Int32 j=1;j 5;j++) this- Invoke(wyswietlDelegat1, safe_cast System::Object^ ´(nr+ _ +j.ToString()+ , )); } finally {Monitor::Exit(this);} */ } Podstawowym dziaáaniem jest wypisanie piĊciu liczb do pola tekstowego w pĊtli for zgodnie z zasadami pisania do kontrolek przez wątki, czyli z uĪyciem delegatów i me- tody Invoke(). Dodatkowo wypisywany jest teĪ numer wątku. Schemat wpisu w jednym kroku pĊtli wygląda tak: Numer Wątku_kolejna liczba Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 333 Na przykáad liczba dwa wypisana przez wątek pierwszy bĊdzie w postaci 1_2. W podanej formie uruchomi siĊ wariant pierwszy, bo wariant drugi jest w bloku komentarza. UĪycie klasy Monitor jest takie jak w wyjaĞnieniach teoretycznych. Obiektem zamykanym do wyáącznego dostĊpu w sekcji krytycznej jest gáówne okno aplikacji, czyli obiekt klasy Form1, który jest dostĊpny we wskaĨniku this, poniewaĪ metody wątku są metodami tej klasy. Pozostaáo zaprogramowanie naciĞniĊcia przycisku button1. BĊdzie on tworzyá trzy wątki i uruchamiaá je. NaciĞnij dwukrotnie ten przycisk w widoku projektowania i uzupeánij metodĊ button1_Click() jak niĪej: private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ t1 = gcnew Thread(gcnew ParameterizedThreadStart(this, Form1::watek)); t1- Start(1); Thread^ t2 = gcnew Thread(gcnew ParameterizedThreadStart(this, Form1::watek)); t2- Start(2); Thread^ t3 = gcnew Thread(gcnew ParameterizedThreadStart(this, Form1::watek)); t3- Start(3); } Uruchom aplikacjĊ i naciĞnij przycisk w oknie. W polu tekstowym zobaczysz napisy jak na rysunku 19.3. Rysunek 19.3. Wynik dziaáania aplikacji bez sekcji krytycznej W ostatniej linii masz wszystkie napisy wygenerowane przez wątki. Prawdopodobnie (nie jest to w 100 pewne, bo zaleĪy od szybkoĞci wykonywania niezaleĪnych wątków) bĊdziesz miaá tam liczbĊ jeden wpisaną przez wątek pierwszy, drugi i trzeci, nastĊp- nie liczbĊ dwa wpisaną przez kolejne wątki i tak dalej. Na rysunku 19.3 wáaĞnie tak jest. Teraz uruchomimy wariant drugi. Zdejmij znaki komentarzy /* i */ z tego warian- tu, a wariant pierwszy zasáoĔ znakiem komentarza. private: System::Void watek(Object^ nr) { wyswDelegat^ wyswietlDelegat1 = gcnew wyswDelegat(this, Form1::wyswietl1); //wariant 1 bez kontroli //for (System::Int32 j=1;j 5;j++) //this- Invoke(wyswietlDelegat1, safe_cast System::Object^ //(nr+ _ +j.ToString()+ , )); //wariant 2 sekcja krytyczna Monitor::Enter(this); //blokada dostepu do calej klasy Form1 334 Microsoft Visual C++ 2012. Praktyczne przykäady try { for (System::Int32 j=1;j 5;j++) this- Invoke(wyswietlDelegat1, safe_cast System::Object^ ´(nr+ _ +j.ToString()+ , )); } finally {Monitor::Exit(this);} } Uruchom aplikacjĊ. Teraz napisy są jak na rysunku 19.4. Rysunek 19.4. Aplikacja z wątkami w sekcji krytycznej W ostatniej linii widaü (teraz mamy pewnoĞü, Īe tak jest), Īe najpierw swoje liczby wpisaá wątek pierwszy, nastĊpnie drugi i trzeci. Podczas kiedy jeden wątek pisaá, inne byáy zawieszone. MoĪliwa jest zmiana kolejnoĞci wykonywania wątków. ZaleĪy to od wielu czynników, ale kiedy wątek zostanie dopuszczony do sekcji krytycznej, bĊdzie mógá spokojnie dziaáaü, mając wyáączny dostĊp do okna. Komponent BackgroundWorker Komponent BackgroundWorker jest kolejną moĪliwoĞcią implementacji wielowątko- woĞci. Za jego pomocą moĪna uruchamiaü metody w wątkach i kontrolowaü ich wy- konanie. Jego funkcjonowanie opiera siĊ na zdarzeniach. Tabela 19.1 przedstawia trzy waĪne zdarzenia związane z tym komponentem. Tabela 19.1. Zdarzenia komponentu BackgroundWorker Zdarzenie DoWork ProgressChanged RunWorkerCompleted Opis Zdarzenie generowane przy rozpoczĊciu dziaáania wątku. Metoda obsáugi tego zdarzenia uruchamia metodĊ wątku. Zdarzenie wystĊpujące w trakcie dziaáania wątku, po wywoáaniu metody ReportProgress(). MoĪe byü uĪyte do pokazywania postĊpu wykonania wątku lub do innych celów wymagających komunikacji z komponentami okna gáównego. Zdarzenie to wystĊpuje po zakoĔczeniu pracy przez metodĊ wątku. Rozdziaä 19. i Podstawy aplikacji wielowñtkowych 335 NajczĊĞciej uĪywane metody tego komponentu przedstawia tabela 19.2. Tabela 19.2. Niektóre metody komponentu BackgroundWorker Metoda RunWorkerAsync() RunWorkerAsync (Object^ parametr) ReportProgress(int postÚp) CancelAsync() Dziaäanie Generuje zdarzenie DoWork, które uruchamia proces w tle. Wersja z parametrem przekazuje parametr do metody wątku. Generuje zdarzenie ProgressChanged. Przekazuje do niego liczbĊ typu int, która moĪe wyraĪaü stopieĔ zaawansowania wątku. Metoda do przerywania dziaáania wątku. Nie przerywa ona jego dziaáania natychmiast, a jedynie ustawia wáaĞciwoĞü CancellationPending na true. Metoda wątku powinna okresowo sprawdzaü tĊ wáaĞciwoĞü i przerwaü wykonywanie wątku. Obiekt BackgroundWorker posiada takĪe wáaĞciwoĞci kontrolujące jego zachowanie. Prezentuje je tabela 19.3. Tabela 19.3.WáaĞciwoĞci komponentu BackgroundWorker WäaĈciwoĈè WorkerReportsProgress WorkerSupportsCanceletion CancellationPending Opis WartoĞü true powoduje, Īe moĪna korzystaü z metody ReportProgress(). UmoĪliwia dziaáanie mechanizmu przerywania wątku. WartoĞü true oznacza, Īe wywoáano metodĊ CancelAsync(). Napiszemy teraz program obliczający w wątku Ğrednią z liczb
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Microsoft Visual C++ 2012. Praktyczne przykłady
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ą: