Zaawansowane programowanie w C++ (ZPR) Wykªad 9 - w tki, std::thread Robert Nowak 2017L Zaawansowane programowanie w C++ (ZPR) 1/34
Równolegªo± - obliczenia podczas obsªugi urz dze«bardzo wolna reakcja czªowieka wolne urz dzenia wej±cia - wyj±cia (np. drukarki) bardzo szybkie procesory PC AT (1987) PC (2017) Poprawa zegar procesora 6 MHz 3.3 GHz 500x ilo± rdzeni (procesorów) 1 4 4x pami wielko± 1MB 16 GB 16000x pami (czas dost pu) 200 ns 40 ns 5x pami (czas dost pu/cykl) 1.4 150-100x rodzaj pami ci wielko± czas dost pu (cykle procesora) cache L1 64kB 2 cache L2 1MB 14 cache L3 8MB 14 DRAM 16GB 150 HDD 1000GB 15000000 Zaawansowane programowanie w C++ (ZPR) 2/34
Graczne porównanie czasów realizacji operacji 1 1 zakªadaj c 1GB/sec SSD, dane z Peter Norvig, Teach Yourself Programming in Ten Years, 2014 Zaawansowane programowanie w C++ (ZPR) 3/34
Wspóªbie»no± wieloprocesowe systemy operacyjne na platformach jedno-procesorowych (jedno-rdzeniowych) na platformach wieloprocesorowych (wielordzeniowych) aplikacje wielow tkowe W tek (lekki proces), pozwala realizowa niezale»ne ci gi instrukcji w ramach procesu. w tki wspóªdziel kod, dane oraz zasoby. mechanizm przeª czania nie wprowadza du»ych narzutów Zaawansowane programowanie w C++ (ZPR) 4/34
Aplikacja wielow tkowa pozwala na reakcj na zlecenia u»ytkownika podczas przeprowadzania oblicze«lepiej wykorzystuje dost pn moc obliczeniow (szczególnie na platformach wieloprocesorowych) mo»e obsªugiwa wiele zlece«równolegle poprawnie zaprojektowana jest szybsza na platformach wieloprocesorowych (wielordzeniowych) Zaawansowane programowanie w C++ (ZPR) 5/34
C++ pozwala implementowa aplikacje wielow tkowe Wspóªdzielone obiekty globalne obiekty dynamiczne (adres jest unikalny niezale»nie od w tku) obiekty automatyczne je»eli dost p jest przez wska¹nik lub referencje zasoby systemu operacyjnego (pliki, okna itp) kod wykonywany Niezale»ne rejestry ci g wykonywanych instrukcji stos zmienne automatyczne Program ma zawsze jeden w tek (funkcja main() ) - w tek gªówny lub inicjuj cy. Mo»e tworzy dodatkowe w tki. Zaawansowane programowanie w C++ (ZPR) 6/34
W tki w C++ Zabronione funkcje biblioteki standardowej (przechowuj stan pomi dzy woªaniami): funkcja biblioteka zamiennik rand cstdlib boost random strtok cstring boost tokenizer lub boost regex asctime ctime localtime gmtime ctime boost date_time nale»y u»ywa bibliotek przeznaczonych do pracy wielow tkowej standard C++03 nie dostarczaª mechanizmów tworzenia i synchronizacji w tków, standard C++11 ma te mechanizmy, mo»na byªo u»ywa w tków mechanizmami dostarczanymi przez system operacyjny Zaawansowane programowanie w C++ (ZPR) 7/34
Biblioteka boost::date_time nazwa opis size date data (gregoria«ska) od 1 stycznia 4B 1400 do 31 grudnia 9999 date_duration dªugo± w czasie (w dniach) 4B date_period przedziaª czasu 8B ptime punkt w czasie (date i 8 lub 12B time_duration). Dokªadno± ms, ale mo»e by ns (wi kszy obiekt). time_duration dªugo± w czasie 4 lub 8B time_period przedziaª czasu 16 lub 24B gregorian::date d(2011,gregorian::apr,20); //data 20 kwietnia 2011 posix_time::ptime t1(d,posix_time::time_duration(18,0,0) );//18:00 posix_time::ptime t2(d, posix_time::hours(12)+posix_time::seconds(4)); posix_time::time_duration td = t2 - t1; //odejmowanie, 4 sekundy posix_time::ptime t3 = t2 + td*10; //mno»enie przez liczb Zaawansowane programowanie w C++ (ZPR) 8/34
Biblioteka std::chrono (boost::chrono) Biblioteka wykorzystywana w boost::thread (od wersji 1.49) nazwa opis time_point reprezentuje punkt w czasie duration dªugo± w czasie, przechowuje liczb cykli oraz dªugo± cyklu clock dostarcza funkcji now, bie» cy punkt w czasie #include <chrono> duration<long, milli > d1; //licznik milisekund u»ywaj c typu long duration<int, ratio<60> > d2; //licznik minut u»ywaj c typu int this_thread::sleep_for( milliseconds(1000)); //argument typu duration system_clock::time_point time_limit = system_clock::now() + seconds(1); this_thread::sleep_until(time_limit); //wykorzystuje time_point Zaawansowane programowanie w C++ (ZPR) 9/34
std::thread - w tki w C++ #include <thread> //Funkcja gªówna w tku u»ytkownika void my_thread() { /*... */ } //Mo»na te» u»y funktora class MyThread { public: //tutaj implementacja funkcji w tku u»ytkownika void operator()() { /*... */ } }; int main() { std::thread thrd(&my_thread); //Utworzenie i uruchomienie w tku try { thrd.join(); //Bie» cy watek czeka na zako«czenie w tku thrd } catch(...) { } //wyj tek zgªaszany, gdy w tek ju» nie istnieje return 0; } Zaawansowane programowanie w C++ (ZPR) 10/34
Wy±cigi (race conditions) wiele w tków pisze lub czyta t sam pami niewªa±ciwa warto± niezdeniowane zachowanie jedno z rozwi za«: synchronizacja (blokady) Zaawansowane programowanie w C++ (ZPR) 11/34
Blokady w boost, mutex (mutual-execution) jest u»ywany do problemu wykluczania. Stany: zablokowany, odblokowany. #include <mutex> mutex.lock(); //Sekcja krytyczna mutex.unlock(); //Utworzenie obiektu sªu» cego do synchronizacji std::mutex mutex_resource; /*... */ { //lock_guard - konstruktor: lock, destruktor: unlock //boost::scoped_lock std::lock_guard guard(mutex_resource); //Tutaj dost p do zasobu }//Tutaj zwolnienie zasobu Zaawansowane programowanie w C++ (ZPR) 12/34
Zakleszczenia (deadlock) ka»dy z w tków czeka na jaki± inny (jest blokowany). aden z nich nie mo»e dalej pracowa. Rozwi zanie: zajmowanie blokad zawsze w tej samej kolejno±ci stosowanie innych mechanizmów synchronizuj cych Zaawansowane programowanie w C++ (ZPR) 13/34
Samo-zakleszczenie brak zwalniania sekcji krytycznej (np. w algorytmach rekurencyjnych) struct Foo { mutex m; void recfun(){ std::lock_guard l(m); /*... */ recfun();//woªanie rekurencyjne }; Rozwi zanie: std::recursive_mutex Zaawansowane programowanie w C++ (ZPR) 14/34
Rodzaje prostych blokad w boost std::mutex lock wolny: zajmuje, zaj ty: blokuje try_lock wolny: zajmuje (zwraca true), zaj ty (zwraca false) std::recursive_mutex lock jak wy»ej try_lock jak wy»ej try_lock_for(time duration) try_lock_until(time point) wolny: zajmuje (zwraca true), zaj ty: blokuje na dany czas Zaawansowane programowanie w C++ (ZPR) 15/34
Typowe ko«czenie w tku nie ma mo»liwo±ci przerwania w tku z zewn trz class MyThread { public: MyThread() : finish_(false) {} void finish() { finish_ = true; } void operator()() { while(!finish_) { //tutaj cz ± przetwarzania //a nast pnie sprawdzanie warunku!finish_ } } private: volatile bool finish_; }; Zaawansowane programowanie w C++ (ZPR) 16/34
W tki i mechanizm wyj tków wyj tki s mog by rzucane i wyªapywane w niezale»nych w tkach w tek nie powinien rzuca wyj tku, który b dzie wyªapywany w innym w tku class MyThread { //... void operator()() { //funkcja w tku u»ytkownika try { //... } catch(...) { /* Wyªapuje wszystkie wyj tki */ } } }; Zaawansowane programowanie w C++ (ZPR) 17/34
Skalowalno± - zapewnienie bardziej wydajnej pracy przy zwi kszaniu zasobów W tki mog pracowa niezale»nie gdy: odczytuj wspóªdzielone dane zapisuj wªasne (lokalne) dane zapis wspóªdzielonych danych jest kªopotliwy (spowalnia) Wyró»nia si szybk i woln ±cie»k w funkcjach wykonywanych w w tkach brak blokad na szybkiej ±cie»ce (blokady, wykorzystywane nawet tylko do odczytu zapisuj stan) usuwanie wspóªdzielonych obiektów do zapisu (lepiej informacj wyj±ciw przechowywa niezale»nie dla ka»dego w tka, a pó¹niej scala wynik) Zaawansowane programowanie w C++ (ZPR) 18/34
Problem czytelników i pisarzy Bardziej skomplikowany (od problemu wykluczania): czytelnicy: w tki nie wykluczaj ce si nawzajem pisarze: w tki wykluczaj ce ka»dy inny w tek, zarówno czytelnika jak i pisarza boost::shared_mutex (std::shared_mutex w C++14) M::lock, M::try_lock, M::timed_lock M::lock_shared, M::try_lock_shared, M::timed_lock_shared Zaawansowane programowanie w C++ (ZPR) 19/34
Zagªodzenia (starvation) dany w tek nie mo»e si wykonywa, poniewa» caªy czas jest blokowany Zaawansowane programowanie w C++ (ZPR) 20/34
problemy z usuwaniem bª dów w aplikacjach wielow tkowych niektóre bª dy s niepowtarzalne ró»ne zachowanie si wersji debug od release testy na platformach z jednym procesorem (rdzeniem) mog nie pokazywa bª dów które wyst pi na platformach posiadaj cych wiele procesorów (rdzeni) trudno testowa wszystkie mo»liwe przebiegi sterowania Zaawansowane programowanie w C++ (ZPR) 21/34
Wzorzec projektowy monitora (pasywny obiekt) Monitor: dostarcza metod, które mog by woªane przez wiele ró»nych w tków. Obiekt sam zapewnia synchronizacj. //monitor, najprostsze rozwi zanie: wewn trzny mutex class InOutQueue : public InOut { std::queue<char> dane_; std::mutex mutex; public: virtual void put(char c) { std::lock_guard guard(mutex); dane_.push(c); } virtual bool get(char& c) { bool read = false; while(!read) { std::lock_guard guard(mutex); if(! dane_.empty() ) { c = dane_.front(); /*... */ } } }; Zaawansowane programowanie w C++ (ZPR) 22/34
Przetwarzanie potokowe algorytmy wykorzystuj ce przetwarzanie potokowe wygodnie tworzy przy wykorzystaniu w tków Zaawansowane programowanie w C++ (ZPR) 23/34
Aktywny obiekt Asynchroniczne woªanie komend komenda wykonuje si w niezale»nym w tku Zaawansowane programowanie w C++ (ZPR) 24/34
Aktywny obiekt - scenariusz komendy nie zwracaj ce wyniku komendy zwracaj ce wynik Zaawansowane programowanie w C++ (ZPR) 25/34
Aktywny obiekt: przykªad implementacji mt4cpp.sourceforge.net #include <mt4cpp/scheduler.hpp> struct DummyCmd : public mt4cpp::command { DummyCmd() {} virtual ~DummyCmd() {} virtual void operator()(mt4cpp::progress& progress) { /*... */ progress.setprogress(0.5);//wiadomo± o post pie /*... */ } }; using namespace mt4cpp; Scheduler scheduler(1); //liczba w tków w puli PCommand cmd(new DummyCmd ); scheduler.executeasynchronously( cmd ); //scheduler.executesynchronously( cmd ); Zaawansowane programowanie w C++ (ZPR) 26/34
boost::asio - asynchroniczne wej±cie/wyj±cie biblioteka skªada si tylko z nagªówków u»ywa: boost_system (kody bª dów), boost_date_time, boost_thread Zawiera przeno±n obsªug : zegarów (timer) gniazd (socket) UDP, TCP (oraz strumieni z nimi zwi zanych) portów szeregowych i in. Windows 95 itp. Win32 (Windows NT itp), Win64 Linux (j dra: 2.4, 2.6) Mac OS X, Solaris i in. Zaawansowane programowanie w C++ (ZPR) 27/34
boost::asio - zegary //Funkcja woªana, gdy zajdzie odpowiednie zdarzenie void event(const boost::system::error_code&) { cout << "timer 2 event" << endl; } int main() { boost::asio::io_service io; //obiekt obsªuguj cy zdarzenia boost::asio::deadline_timer t1(io, boost::posix_time::seconds(3)); t1.wait(); //rejestracja zdarzenia i wykonanie synchroniczne cout << "timer 1 event" << endl; boost::asio::deadline_timer t2(io, boost::posix_time::seconds(3)); t2.async_wait(event); //rejestracja zdarzenia i wykonanie synchr. io.run(); //obsªuga zdarze«asynchronicznych return 0; } Zaawansowane programowanie w C++ (ZPR) 28/34
boost::asio, porty szeregowe typedef vector<char> Buffer; typedef steady_timer::duration Timeout; class SerialPort { public: SerialPort(const std::string& port_name, const Timeout timeout) : timeout_(timeout), io_(), port_(io_, port_name ), timer_(io_) { } ~SerialPort() { port_.close(); } const Buffer& read_n(int n) { timer_.expires_from_now( timeout_ ); timer_.async_wait(bind(&serialport::timerevent, this, placeholders:: readsomecall(n); io_.run(); return readbuffer_; } private: Timeout timeout_; io_service io_; serial_port port_;//port szeregowy steady_timer timer_; //zegar char buffer_ [1]; //bufor transmisji Buffer readbuffer_; //bufor odczytu //... Zaawansowane programowanie w C++ (ZPR) 29/34
boost::asio, porty szeregowe (2) //... void readsomecall(int n) { port_.async_read_some( buffer(buffer_), bind(&serialport::readevent, this, placeholders::error, n)); } void readevent(const error_code& error, int n) { if( error ) return; //je»eli wyst piª bª d odczytu readbuffer_.push_back(buffer_[0]); if(readbuffer_.size()>=n){timer_.cancel();return;}//koniec czytania readsomecall(n); } void timerevent(const error_code& error) { if( error ) return; //je»eli zdarzenie wycofane, to nic nie rób port_.cancel(); //wygeneruje zdarzenie odczytu z bª dem } }; mt4cpp.sourceforge.net mt4cpp::serialport s("com20", boost::chrono::milliseconds(50) ); std::vector<char> in = s.read_n(3); //czyta 3 bajty albo timeout Zaawansowane programowanie w C++ (ZPR) 30/34
boost::asio - obsªuga sieci std::size_t completion(error_code& error, std::size_t ) { /* */ } int main() { io_service io_service;//obsªuguje» dania wej±cia-wyj±cia ip::address address = ip::address::from_string("127.0.0.1"); ip::tcp::endpoint endpoint(address, 80); ip::tcp::socket socket(io_service); socket.connect(endpoint);//nawi zanie poª czenia synchroniczne streambuf request;//» danie wysyªane do serwera www std::ostream request_stream(&request); request_stream << "GET index.html HTTP/1.0\r\n" << "Host: localhost\r\n" << "Accept: */*\r\n" << "Connection: close\r\n\r\n"; write(socket, request);//synchronicznie wysyªa» danie streambuf response; error_code ec; read(socket, response, completion, ec); //odczytuje odpowied¹ std::cout << &response; return 0; } Zaawansowane programowanie w C++ (ZPR) 31/34
biblioteki boost zwi zane ze wspóªbie»no±ci boost::interprocess - komunikacja pomi dzy procesami Przeno±ne mechanizmy komunikacji pomi dzy procesami (aplikacjami). pami dzielona (shared memory) mechanizmy synchronizuj ce w tej pami ci (semafory, zmienne warunkowe komunikacja przez pliki kolejki komunikatów std::atomic (C++11), boost::atomic - operacje atomowe obiekty, które gwarantuj niepodzielno± wykonywanych na nich operacji kolekcje wspóªbie»ne nie u»ywaj ce blokad Zaawansowane programowanie w C++ (ZPR) 32/34
Podsumowanie aplikacje wielow tkowe s coraz bardziej powszechne boost zapewnia obiekty reprezentuj ce w tki oraz mechanizmy synchronizacyjne obsªuga w tków zostaªa dodana do C++11 biblioteka ACE (Adaptive Communication Environment) OpenMP - interfejs do tworzenia aplikacji wykorzystuj cych wspóªbie»no± OpenCL - biblioteka do tworzenia algorytmów wykonywanych na CPU i/lub GPU Zaawansowane programowanie w C++ (ZPR) 33/34
Dodatkowa lektura (http://staff.elka.pw.edu.pl/~rnowak2/rnbib.html): R. Nowak, Aktywny obiekt - wspóªbie»no± i komendy, Software Developer's Journal, 2010. R. Nowak, Wspóªdzielenie obiektów w aplikacjach wspóªbie»nych, Software Developer's Journal, 2010. R. Nowak, Asynchroniczna obsªuga urz dze«wej±cia-wyj±cia, Software Developer's Journal, 2010. R. Nowak, Wspóªbie»na obsªuga zdarze«bez w tków, Programista, 2013. Dzi kuj