Wykład 6 Programowanie systemowe w Linux: Wątki i ich synchronizacja

Slides:



Advertisements
Podobne prezentacje
Introduction to SystemC
Advertisements

Analiza wywołania i przebiegu przerwań w systemie Linux
C++ w Objectivity Marcin Michalak s1744. Pomocne pakiety: Data Definition Language (DDL). Standard Template Library (STL). Active Schema.
Systemy operacyjne Wykład nr 5: Wątki Piotr Bilski.
Testowanie oprogramowania metodą badania pokrycia kodu
142 JAVA – sterowanie i wątki public class A20 extends javax.swing.JApplet implements ActionListener { private int licznik = 0; private JTextField t =
REKURENCJA.
Czyli jak zrobić prezentację komputerową?
Małgorzata Pietroczuk
Tajemnice klawiatury.
Zastosowanie Internetu
Operacjonalizacja problematyki badawczej
Systemy klastrowe inaczej klasterowe.
Elektronika cyfrowa Prezentacja Remka Kondrackiego.
Prąd Elektryczny.
AUTOR :WOJTEK NOWIK REPORTER : LUK SMIS PATRYK SORMAN PIOTREK COLO (KOLO)
Autorzy: Agnieszka Kuraj Natalia Gałuszka Kl. III c.
To jest bardzo proste  Lekcja nr 3
Podstawy programowania
Przewodnik dla początkujących
Microsoft® Office EXCEL 2003
Co każdy użytkownik komputera wiedzieć powinien
ST/PRM2-EU | April 2013 | © Robert Bosch GmbH All rights reserved, also regarding any disposal, exploitation, reproduction, editing, distribution,
Ach te baby... Ach te baby....
ALGORYTMY.
ALGORYTM.
Technologię informatyczną wykorzystywana jest na tych zajęciach w dwojaki sposób: Przy użyciu płyt CD, które są jednym z elementów obudowy programu Matematyka.
PRAWIDŁOWA SYLWETKA.
Wykonała Sylwia Kozber
Cz.8 Zdarzenia. Refleksja – przypomnienie Event Programowanie zdarzeniowe Do dzieła!
Antonie de Saint-Exupery
xHTML jako rozszerzenie HTML
Instalacja serwera WWW na komputerze lokalnym
PHP Operacje na datach Damian Urbańczyk. Operacje na datach? Dzięki odpowiednim funkcjom PHP, możemy dokonywać operacji na datach. Funkcje date() i time()
HTML Podstawy języka hipertekstowego Damian Urbańczyk.
PATOLOGIE SPOŁECZNE. Ubóstwo i bezrobocie SPOSOBY ZWALCZANIA UBÓSTWA I BEZROBOCIA System opieki społecznej Programy aktywneProgramy pasywne.
Bank Wielkopostny to ogólnopolska akcja ewangelizacyjna; dobry i pożyteczny sposób na aktywne przeżycie okresu Wielkiego Postu i przygotowanie się do.
Optyka Widmo Światła Białego Dyfrakcja i Interferencja
Przygotowali : Szymon, Filip i Piotrek
J AK ZACZĄĆ PRACĘ Z ?. przed rejestracją Upewnij się, że posiadasz: aktywne konto zainstalowaną przeglądarkę Internet Explorer indywidualny studencki.
SKĄD WIEM, KIM JESTEM? O TOŻSAMOśCI I TOŻSAMOŚCIACH
Warsztaty C# Część 3 Grzegorz Piotrowski Grupa.NET PO
KINECT – czyli z czym to się je?. Damian Zawada
Opracowała: Iwona Kowalik
BEZPIECZNY INTERNET. PRZEGLĄDANIE STRON INTERNETOWYCH.
Sieci komputerowe. Nowe technologie komputerowe
To śmieszne...
Lokalne konta użytkowników i grup
Bazy danych.
Pliki elementowe – A. Jędryczkowski © 2007 Turbo Pascal umożliwia wykorzystanie w programach plików elementowych. Pliki takie zawierają informację zakodowaną
Budowa programu #include /*instrukcje preprocesora */ #include int main(void) { /*podstawowa funkcja programu */ int a=1; /*deklaracja i inicjalizacja.
Procesy i wątki dla dociekliwych
Strategie badań – ilościowe v. jakościowe - porównanie
PROGRAMOWANIE SYSTEMOWE [1/3]
W.K. (c) Bazy danych Access. 2W.K. (c) 2007 Baza danych - definicje Baza danych to zbiór informacji dotyczących określonego tematu (stanowiących.
Temat 5: Elementy meta.
Temat 1: Umieszczanie skryptów w dokumencie
Informacje podstawowe
Procesy poznawcze WPROWADZENIE.
Architektura systemów komputerowych zima 2013 Wykład 1 (cz. a) Wprowadzenie dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki
WoF PLATFORMA KOMUNIKACJI. WoF jest platformą komunikacji systemem wspomagającym obieg informacji oraz zarządzanie w firmie Zapewnia elektroniczny obieg.
Warsztaty użytkowników programu PLANS – Karwia06 Język makropoleceń JMP programu PLANS Część I mgr inż. Tomasz Zdun.
Instrukcja switch switch (wyrażenie) { case wart_1 : { instr_1; break; } case wart_2 : { instr_2; break; } … case wart_n : { instr_n; break; } default.
Instrukcja switch switch (wyrażenie) { case wart_1 : { instr_1; break; } case wart_2 : { instr_2; break; } … case wart_n : { instr_n; break; } default.
Instrukcje sterujące: W instrukcjach sterujących podejmowane są decyzje o wykonaniu tych czy innych instrukcji programu. Decyzje te podejmowane są w zależności.
Magic Janusz ROŻEJ Komtech Sp. z o.o.
Komtech Sp. z o.o. Magic Janusz ROŻEJ.
Magic Janusz ROŻEJ Komtech Sp. z o.o.
w/g Grzegorz Gadomskiego
Największym bólem w życiu nie jest śmierć, lecz bycie ignorowanym.
Zapis prezentacji:

Wykład 6 Programowanie systemowe w Linux: Wątki i ich synchronizacja UNIX jesień/zima 2013 Wykład 6 Programowanie systemowe w Linux: Wątki i ich synchronizacja dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz

Wielowątkowość – powtórzenie Jeden proces może wykonywać się w wielu współbieżnych wątkach (ang. thread). Każdy wątek (inna nazwa: proces lekki, ang. lightweight process) – Ma swój własny stan (Aktywny, Gotowy, Zablokowany, ... ) – Ma swoje wartości rejestrów i licznika rozkazów. – Ma swój własny stos (zmienne lokalne funkcji). – Ma dostęp do przestrzeni adresowej, plików i innych zasobów procesu. Wszystkie wątki procesu współdzielą te zasoby. Procesy są od siebie izolowane, wątki nie ! Operacje zakończenia, zawieszenia procesu dotyczą wszystkich wątków. Przełączanie pomiędzy równoprawnymi wątkami jest „tanie” (szybsze) w porównaniu z przełączaniem pomiędzy tradycyjnymi procesami (nie trzeba przełączać kontekstu pamięci). Wątki zyskują na popularności ponieważ – mając pewne cechy ciężkich procesów – są efektywniejsze w działaniu.

Schemat procesu i wątków Przestrzeń adresowa Otwarte pliki Procesy potomne Obsługa sygnałów Sprawozdawczość Zmienne globalne Wątek 1 Licznik rozkazów Rejestry Stos i wskaźnik stosu Stan Wątek 2 Licznik rozkazów Rejestry Stos i wskaźnik stosu Stan Wątek 2 Licznik rozkazów Rejestry Stos i wskaźnik stosu Stan

Diagram przejść pomiędzy stanami wątku w UNIX

Proces z wątkami – w zależności od implementacji Standardowy Unix MS-DOS Linux, MS-Windows, POSIX, OS/2, Solaris

Wątki na poziomie użytkownika ang. user-level threads System operacyjny nie jest świadom istnienia wątków. Zarządzanie wątkami jest przeprowadzane przez bibliotekę w przestrzeni użytkownika. Przykład: Wątek A wywołuje funkcję read. Standardowo funkcja systemowa read jest synchroniczna (usypia do momentu zakończenia operacji). Jednak implementacja w bibliotece wywołuje wersję asynchroniczną i przełącza się do wątku B. Rozwiązanie to jest szybkie, ma jednak wady: – Dwa wątki nie mogą się wykonywać współbieżnie na dwóch różnych procesorach. – Nie można odebrać procesora jednemu wątkowi i przekazać drugiemu

Wątki na poziomie jądra ang. kernel-level threads Wątek jest jednostką systemu operacyjnego. Wątki podlegają szeregowaniu przez jądro. W systemie SMP* wątki mogą się wykonywać na różnych procesorach – przetwarzanie równoległe. Windows i Linux wykorzystują tę metodę. *) SMP (ang. Symmetric Multiprocessing, przetwarzanie symetryczne) - architektura komputerowa, która pozwala na znaczne zwiększenie mocy obliczeniowej systemu komputerowego poprzez wykorzystanie dwóch lub więcej procesorów do jednoczesnego wykonywania zadań.

Implementacja wątków w POSIX Program korzystający z funkcji operujących na wątkach POSIX musi zawierać dyrektywę #include <pthread.h> Kompilując przy użyciu gcc programy korzystające z tej biblioteki, należy wymusić jej dołączenie, przez użycie opcji -lpthread: gcc -lpthread program.c Każdy proces zawiera przynajmniej jeden główny wątek początkowy, tworzony przez system operacyjny w momencie stworzenia procesu. Aby do procesu dodać nowy wątek należy wywołać funkcję pthread_create. Nowo utworzony wątek zaczyna się od wykonania funkcji użytkownika przekazanej jako argument pthread_create. Wątek działa aż do czasu wystąpienia jednego z następujących zdarzeń: zakończenia funkcji, wywołania funkcji pthread_exit, anulowania wątku za pomocą funkcji pthread_cancel, zakończenia procesu macierzystego wątku, wywołania funkcji exec przez jeden z wątków.

Przykład użycia funkcji pthread_create Funkcja pthread_create tworzy nowy wątek. Rozpoczyna on pracę od funkcji, której adres przekazano jako trzeci argument. void *wat_fun(void *param) { // tu kod wątku // możemy przekazać wynik return NULL; } Funkcja pthread_join usypia wywołujący ją wątek do momentu, kiedy wątek o identyfikatorze przekazanym jako pierwszy argument zakończy pracę. int main() { pthread_t id; // Parametr przekazywany wątkowi void *param=NULL; pthread_create(&id,NULL,&wat_fun,param); // Funkcja thread w odrębnym wątku współbieżnie z main. // id przechowuje identyfikator wątku void *result; // Czekaj na zakończenie wątku pthread_join(id,&result); // Wynik w result, zamiast &result można przekazać NULL } Zakończenie pracy wątku – powrót z funkcji, która go rozpoczyna.

Opis funkcji systemowych pthread_create(pthread_t *thread, pthread_attr_t *attr, void*(*start_routine) (void*),void *arg) W Linuxie wątki mogą być tworzone poprzez funkcję pthread_create(). Podobnie jak fork() funkcja pthread_create() tworzy nowy kontekst wykonywania. Nowy wątek współdzieli z tworzącym go procesem PID, przestrzeń adresową, deskryptory plików itp. Wątek kończy swoje działanie w momencie kiedy skończy się wykonywanie funkcji wskazywanej przez start_routine przekazanej jako parametr do pthread_create(). Parametry funkcji wskazywanej przez start_routine czyli parametr arg muszą być przekazane przez wskaźnik na obszar pamięci (zmienną prostą lub strukturę), który zawiera odpowiednie wartości. Parametr attr wskazuje na atrybuty wątku, a przez wskaźnik thread zwracany jest identyfikator wątku.

Opis funkcji systemowych W Linuxie wątki mogą być także tworzone poprzez funkcję clone(). W rzeczywistości funkcja ta tworzy nowy proces, tak jak fork(), ale pozwala procesowi potomnemu współdzielić z procesem wywołującym część kontekstu wykonania (obszar pamięci, tablica deskryptorów plików, tablica programów obsługi sygnałów) int clone(int (*fn)(void*), void*child_stack, int flags, void*arg); Różnica pomiędzy pthread_create() a clone(). Można wskazać: które typy zasobów będą a które nie będą współdzielone (np. identyfikatory plików, uchwyty sygnałów itp.). jaki będzie posiadała PID procesu macierzystego jaki sygnał (jeśli w ogóle) będzie dostarczał informacji twórcy wątku o zakończeniu wątku . gdzie będzie umieszczony stos nowego wątku. Wątek kończy swoje działanie w momencie kiedy skończy się wykonywanie funkcji przekazanej jako parametr do clone().

Opis funkcji systemowych pthread_exit(void *retval) zakończenie wątku. Funkcja powoduje zakończenie wątku i przekazanie retval, jako wskaźnika na wynik. Wskaźnik ten może zostać przejęty przez inny wątek, który będzie wykonywał funkcję pthread_join pthread_join(pthread_t th, void **thread_return) oczekiwanie na zakończenie wątku. Funkcja umożliwia zablokowanie wątku w oczekiwaniu na zakończenie innego wątku, identyfikowanego przez parametr th. Jeśli oczekiwany wątek zakończył się wcześniej, funkcja zakończy się natychmiast. Funkcja przekazuje przez parametr thread_return wskaźnik na wynik wątku (wykonywanej przez niego funkcji), przekazany jako parametr funkcji pthread_exit wywołanej w zakończonym wątku. pthread_cancel(pthread_t thread) zakończenie wykonywania innego wątku. Funkcja umożliwia wątkowi usunięcie z systemu innego wątku, identyfikowanego przez parametr thread.

Przykład programu z wątkiem #include <pthread.h> #include <stdlib.h> #include <unistd.h> void *Hello(void *arg) { int i; for ( i=0; i<20; i++ ) { printf("Wątek pisze na ekranie!\n"); sleep(1); } return NULL; int main(void) { pthread_t mojwątek; if ( pthread_create( &mojwątek, NULL, Hello, NULL)){ printf("błąd przy tworzeniu wątku\n"); abort(); if ( pthread_join ( mojwatek, NULL ) ) { printf("błąd w kończeniu wątku\n"); exit(); return 0;

Problem synchronizacji wątków Architektura RISC: ładuj do rejestru, zwiększ wartość, zapisz wynik. Niech x oznacza jest modyfikowaną zmienną counter. Przyjmijmy, że x=5 Rozważmy dwie możliwe kolejności wykonywania instrukcji poszczególnych procesów. – a) Poprawna wartość 5. – b) Niepoprawna wartość 4. Wybór jednej z tych wielkości niedeterministyczny. Sytuacja wyścigu

Problem z synchronizacją #include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> int X=0; void *fun(void *arg) { int i,j; for (i=0; i<20; i++) j=X; j++; printf("O"); fflush(stdout); sleep(1); X=j; } return NULL; int main(void) { pthread_t id_w; int i; if(pthread_create(&id_w,NULL,fun,NULL)) { printf("błąd przy tworzeniu wątku."); abort(); } for ( i=0; i<20; i++) X++; printf("X"); fflush(stdout); sleep(1); if (pthread_join(id_w, NULL)) printf("błąd przy kończeniu wątku."); printf("\nX=%d\n", X); exit(0); Przykład wyścigu

Cechy wątków Zalety Wady – Utworzenie i zakończenie wątku zajmuje znacznie mniej czasu niż w przypadku procesu – Możliwość szybkiego przełączania kontekstu pomiędzy wątkami tego samego procesu – Możliwość komunikacji wątków bez pośrednictwa systemu operacyjnego – Możliwość wykorzystania maszyn wieloprocesorowych Wady Źle zachowujący się wątek może zakłócić pracę innych wątków tego samego procesu. W przypadku dwóch procesów o odrębnych przestrzeniach adresowych nie jest to możliwe

Synchronizacja wątków Stosowane są dwie metody zapewnienia odpowiedniej koordynacji wątków: korzystanie z zamków czyli blokad wzajemnie wykluczających, tzw. muteksów korzystanie z konstrukcji nazywanych zmiennymi warunkowymi. Mutex to inaczej semafor binarny (zezwala na dostęp lub zabrania). Zamknięcia muteksu może dokonać dowolny wątek znajdujący się w jego zasięgu, natomiast otworzyć go może tylko wątek który go zamknął. Wątki, które nie mogą uzyskać dostępu do muteksu są blokowane w oczekiwaniu na niego. Operacje wykonywane na muteksach są niepodzielne. Jeśli za pomocą muteksów trzeba synchronizować wątki kilku procesów, należy odwzorować mutex w obszar pamięci współdzielonej dostępny dla wszystkich procesów.

Synchronizacja wątków Gdy niezbędne jest synchronizowanie wątków za pomocą bieżących wartości danych chronionych muteksami, można użyć konstrukcji nazywanych zmiennymi warunkowymi. Zmienna warunkowa jest kojarzona z konkretnym muteksem i predykatem. Podobnie jak mutex może ona być odwzorowana w pamięć współdzieloną, dzięki czemu może być używana przez parę procesów. Głównym zadaniem zmiennych warunkowych jest powiadamianie innych procesów o tym, że dany warunek został spełniony, lub do blokowania procesu w oczekiwaniu na otrzymanie powiadomienia. W momencie kiedy wątek jest blokowany na zmiennej warunkowej, skojarzony z nim mutex jest zwalniany. W oczekiwaniu na to samo powiadomienie zablokowanych może być kilka wątków. Wątek zgłasza powiadamianie wysyłając sygnał do skojarzonej zmiennej warunkowej.

Opis funkcji systemowych Do zapewnienia wzajemnego wykluczania używana jest zmienna (np. mutex), zadeklarowana następująco: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(pthread_mutex_t *mutex) zajęcie zamka (zajęcie sekcji krytycznej). Funkcja powoduje zajęcie zamka wskazywanego przez parametr mutex, poprzedzone ewentualnym zablokowaniem wątku do czasu zwolnienia zamka, jeśli został on wcześniej zajęty przez inny wątek. pthread_mutex_unlock(pthread_mutex_t *mutex) zwolnienie zamka (zwolnienie sekcji krytycznej). Funkcja powoduje zwolnienie zamka wskazywanego przez parametr mutex, umożliwiając jego zajęcie innemu wątkowi. pthread_mutex_trylock(pthread_mutex_t *mutex) próba zajęcia zamka. Funkcja powoduje zajęcie zamka wskazywanego przez parametr mutex, jeśli nie jest zajęty przez inny wątek. W przeciwnym przypadku zwraca błąd, nie blokując tym samym procesu.

Opis funkcji systemowych Synchronizacja za pomocą zmiennych warunkowych polega na usypianiu i budzeniu wątku w sekcji krytycznej. W tym celu używana jest zmienna warunkowa (tu cond), zadeklarowana następująco: pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) oczekiwanie na sygnał. Funkcja powoduje uśpienie wątku na zmiennej warunkowej, wskazywanej przez parametr cond. Na czas uśpienia wątek zwalnia zamek, wskazywany przez parametr mutex, udostępniając tym samym sekcję krytyczną innym wątkom. Po obudzeniu i wyjściu z funkcji (na skutek odebrania sygnału wysłanego przez pthread_cond_signal) zamek zajmowany jest ponownie. pthread_cond_signal(pthread_cond_t *cond) wysłanie sygnału (obudzenie) do jednego z wątków oczekujących na zmiennej warunkowej wskazywanej przez cond.

Przykład synchronizacji z muteksem #include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> int X; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; void *fun(void *arg) { int i,j; for ( i=0; i<20; i++ ) pthread_mutex_lock(&mut); j = X; j++; printf("O"); fflush(stdout); sleep(1); X = j; pthread_mutex_unlock(&m); } return NULL; int main(void) { pthread_t id_w; int i; if(pthread_create(&id_w,NULL,fun,NULL)) { printf("błąd tworzenia wątku."); abort(); } for ( i=0; i<20; i++) { pthread_mutex_lock(&mut); X++; pthread_mutex_unlock(&mut); printf("o"); fflush(stdout); sleep(1); if(pthread_join(id_w, NULL ) ) { printf("błąd kończenia wątku."); printf("\nX = %d\n", X); exit(0);

Możliwe problemy z wątkami Przykład: errno to uniksowy mechanizm zgłaszania błędów przez funkcje libc, a w szczególności jądra. Jeśli funkcja zakończy się błędem, sygnalizuje to zwracając zwykle -1 lub NULL. Program powinien wtedy zajrzeć do zmiennej globalnej errno, żeby dowiedzieć się jaki dokładnie błąd wystąpił. Jeśli funkcja zakończy się pomyślnie zawartość errno nie jest zdefiniowana.

Możliwe problemy z wątkami #include <stdio.h> /* fprintf */ #include <errno.h> /* errno */ #include <stdlib.h> /* malloc, free, exit */ #include <string.h> /* strerror */ extern int errno; int main( void ) { /* deklaracja wskaźnika do tablicy o pojemności 2GB */ char *ptr = malloc( 2000000000UL ); if ( ptr == NULL ){ puts("malloc failed"); puts(strerror(errno)); } else /* Pomyślnie zaalokowano tablicę free( ptr ); exit(EXIT_SUCCESS); /* exiting program */

Możliwe problemy z wątkami W standardowej bibliotece C, w wersji wielowątkowej, errno jest implementowane jako prywatna zmienna globalna (nie współdzielona z innymi wątkami) Gdy kilka wątków jednocześnie wywołuje funkcje malloc/free - może dojść do uszkodzenia globalnych struktur danych (listy wolnych bloków pamięci) Potrzeba synchronizacji => może prowadzić do spadku wydajności

Inne problemy z wątkami Proces otrzymuje sygnał: – Wszystkie wątki otrzymują sygnał – Wybrany wątek otrzymuje sygnał – Wątek aktualnie aktywny otrzymuje sygnał Proces wykonuje fork. – Czy duplikować jedynie działający wątek, czy też wszystkie wątki ? Proces wywołuje exit. – Zakończyć proces czy też jedynie aktywny wątek ? Anulowanie wątku (ang. cancellation). – Wykonać natychmiast . – Wątek co jakiś czas sprawdza czy nie został anulowany

Literatura Ważniak – laboratorium z systemów operacyjnych http://wazniak.mimuw.edu.pl/index.php?title=Systemy_operacyjne#Laboratorium Wojciech Kwedlo, Wykład z Systemów Operacyjnych Wydział Informatyki Politechniki Białostockiej http://aragorn.pb.bialystok.pl/~wkwedlo/OS-Slides-new.html