Wikipedysta:Thorlak/brudnopis2

WielowątkowośćEdytuj

Wstęp  Edytuj

Ten podręcznik ma na celu wypełnienie luki, która pojawiła się w Wikibooks, w dziale programowanie. Kierowany jest do raczej zaawansowanego czytelnika, który (cytując Tannenbauma) napisał już pięć programów w dowolnym języku o składni przypominającej tą z C.

Każdy programista w pewnym momencie swojej edukacji musi przyjrzeć się temu czym jest wielowątkowość. Gdyby nie ona nadal moglibyśmy korzystać z tylko jednego programu na raz. Bardzo trudno sobie to wyobrazić w czasach, gdy w samej przeglądarce internetowej mamy otwartych 10 zakładek, gdzie z jednej słuchamy muzyki w następnej piszemy na blogu, a w reszcie mamy włączone materiały, z których korzystamy podczas pisania. Przetwarzanie wielowątkowe objawia się na każdym kroku. Żaden szanujący się programista nie może się obejść bez znajomości chociaż podstawowych pojęć związanych ze współbieżnością i rozwiązywaniem podstawowych problemów synchronizacyjnych. Ponadto minimalnie zahaczymy o tematykę systemów operacyjnych, które, jakby nie było, bezpośrednio umożliwiają nam wykorzystanie możliwości jakie daje wielowątkowość.

W podręczniku zawarte zostało omówienie funkcji oferowanych przez pewne standardowe biblioteki oferowane przez poszczególne języki jak w przypadku pthreads oferowanych przez system unixopodobny dla C/C++, czy też samego standardu C++11, który dodaje do tego języka obsługę współbieżności. Ponadto omawiamy tutaj również Javę, która oferuje wielowątkowość za pomocą swojej własnej maszyny wirtualnej i odpowiednich klas standardowych, a także Adę, która jako jedyny język z tutaj zaprezentowanych została zaprojektowana właśnie z myślą o obsłudze wielowątkowości.

Życzymy miłej lektury, Autorzy.

Bibliografia Edytuj

  • Systemy operacyjne. Andrew S. Tannenbaum. Wydawnictwo Helion, 2010.
  • Wprowadzenie do programowania w języku Ada'95. M. Morawski, A. M. Zajączkowski. Skrypt uczelniany Politechniki Łódzkiej, 2004
  • C++. Concurrency in action. Practical multithreading. A. Williams. Wydawnictwo Manning, 2012.
  • Systemy operacyjne. Materiały wykładowe Ważniak.. J. Brzeziński, M. Wawrzyniak. Politechnika Poznańska, 2006.

Procesy w systemie operacjynym Edytuj

System operacyjny to naprawdę świetne narzędzie, ale nie zawsze tak było. Jeszcze nie dawno ( w czasach MS-DOS'a) nadal korzystało się z systemów, które pozwalały na korzystanie z jednego programu na raz. Oczywiście istniały również potężne systemy komputerowe, gdzie jednocześnie korzystało z nich wielu użytkowników i wtedy wykonywanie jednego programu na raz nie byłoby najmądrzejszym z pomysłów. Trzeba więc poprawić nieco nasze stwierdzenie - wielowątkowy system operacyjny to naprawdę świetne narzędzie.

Jednak jego świetność wynika jeszcze z jednego faktu - zapewnia programiście świetną dozę abstrakcji do wykorzystania od zaraz! Zamiast wczytywać dane z dysku bit po bicie udostępnia do wykorzystania pliki ( to są już tak oczywiste sprawy, że w wielu momentach zapominamy o tym co znajduje się pod tą warstwą abstrakcji), z gotowymi mechanizmami dostępu, jak na przykład linuksowa funkcja open. Następnie mamy wszystkie urządzenia peryferyjne, z którymi możemy się bardzo wygodnie komunikować za sprawą systemu operacyjnego.

Najważniejszą jednak abstrakcją, z punktu widzenia tej książki, jaką otrzymujemy są procesy. Na potrzeby tego podręcznika za proces będziemy, przynajmniej na razie, przyjmować taką definicję :

Dla kogoś zupełnie początkującego może się to wydawać dość dziwne, że nawet w jednoprocesorowym systemie można mówić o współbieżności. Przecież w takim wypadku tylko jeden proces może być wykonywany w jednym czasie.

Najpierw trzeba by się zastanowić na samą budową procesora, czyli zejść o jeden poziom abstrakcji niżej. Na poziomie logicznej budowy procesora powinien się on składać z rejestru(rejestrów) - być może znanego- AC, czyli akumulatora oraz ALSU tzn. Arithmetic-Logic-Shifting Unit po polsku jednostki arytmetyczno-logiczno-przesuwającej, za jej pomocą odbywają się wszystkie operacje na liczbach wykonywane przez komputer. Dobrze, ale to nie wszystko, co znajdziemy we współczesnych procesorach, dodatkowo mamy tam FPU, które jeszcze nie dawno było po prostu osobnym procesorem służącym do operacji na liczbach zmiennoprzecinkowych (stąd nazwa Floating Point Unit) po polsku nazywany czasem koprocesorem. Czyli na jednej płytce krzemowej nie większej niż 3cm na 3cm tak na prawdę znajdują się dwa procesory, jeden do operacji na liczbach całkowitych a drugi do operacji na liczbach rzeczywistych.

Teraz możemy wrócić do wyższego poziomu abstrakcji. W pamięci nadal mamy to, że procesor w systemie operacyjnym jest również zasobem, ale takim, który służy do przetwarzania danych, a dane mogą być różnego typu. I ze względu na ten typ system operacyjny może przy wykorzystaniu jednego procesora jednocześnie prowadzić obliczenia. Pod warunkiem, że jeden proces w tym samym kwancie czasu będzie wykonywać kod operujący na floatach, natomiast drugi będzie działać na intach.

Ale to tylko jedna z możliwości jakie mogą się pojawić przy przetwarzaniu współbieżnym. Zastanówmy się nad takim przypadkiem - mamy proces, który po wykonywaniu jakichś obliczeń ( czyli znajduje się "na procesorze") będzie potrzebować dostępu do dysku, jak wiadomo dostęp do pamięci dyskowej jest znacznie wolniejszy od dostępu do pamięci RAM, więc w czasie wykonywania tego żądania równie dobrze jakiś inny proces mógłby wykonywać swoje obliczenia. W takim przypadku mamy do czynienia z pseudowspółbieżnością,w momencie, w którym proces prosi o dostęp do dysku następuje przerwanie sprzętowe związane z obsługą tego żądania, ponadto w określonych przez twórców systemu operacyjnego momentach (na przykład po upłynięciu jakieś arbitralnej wielkości czasu) następują przerwania systemowe, które również służą do wywłaszczenia procesu, dzięki czemu nie dochodzi do sytuacji, w której pewien proces jest "zagłodzony" i nie może wykonywać swojego kodu. W tym momencie możemy podać pewną, skrótową definicję czym jest przetwarzanie współbieżne :

Należy pamiętać, że śledzenie działania programu współbieżnego jest bardzo trudne, dlatego zapobieganie takim sytuacjom jak na przykład zagłodzenie procesu jest bardzo trudne. Z tego powodu powstał pewien model pamięciowy, który ułatwia obsługę współbieżności.

Model procesów Edytuj

Nasz model zakłada, że całe oprogramowanie, włącznie z systemem operacyjnym, jest zorganizowane w postaci zbioru procesów sekwencyjnych. Proces jest egzemplarzem uruchomionego programu, który ideowo będzie mieć własny wirtualny procesor CPU, ponieważ poza kodem, który ma wykonywać proces zawiera licznik programu, zawartość rejestrów oraz zmiennych. Oczywiście w rzeczywistości procesor fizyczny przełącza się z procesu do procesu.

Warto byłoby jeszcze nakreślić dokładnie różnicę między programem a procesem. Proces jest pewnym działaniem, pewnym czynnym aspektem programu, łatwo sobie wyobrazić sytuację, w której do komputera są podłączone dwie drukarki i działają dwa procesy odpowiadające za drukowanie na każdej z nich, przy czym są to dwie kopie tego samego programu albo kilka procesów edytora tekstu działających współbieżnie.

Tak więc program jest zbiorem instrukcji. W tym sensie jest tylko elementem procesu, znajdującym się w jego segmencie kodu. Poza tym do wykonania programu potrzebne są dodatkowe zasoby (procesor, pamięć itp.) Program najczęściej nie zmienia się w czasie wykonywania (nie ulega modyfikacji), chyba, że mamy do czynienia z wirusem, gdzie takie działanie programu służy do utrudnienia zrozumienia tego co robi, podczas gdy stan procesu ulega zmianie: zmienia się stan wykonywania programu podobnie jak stan większości zasobów z tym związanych. Zmianie w wyniku wykonywania procesu ulega np. segment danych, segment stosu, stan rejestrów procesora itp. Procesem jest więc cały ten kontekst niezbędny do wykonania programu, czyli stan wcześniej opisanego wirtualnego CPU.

Kwestia tego, czy system operacyjny faktycznie będzie trzymać w pamięci dwie kopie kodu programu jest już zupełnie inna i jest związana z zagadnieniami teorii budowy systemów operacyjnych.

Obsługa procesów Edytuj

Z obsługą procesów wiąże się kilka elementarnych operacji: tworzenie, usuwanie, zmianę stanu, zmianę priorytetu. Nie wszystkie operacje na procesach są dostępne dla aplikacji. Dlatego też tutaj przyjrzymy się tylko tym ważnym z punktu widzenia programisty aplikacji.

Tworzenie procesówEdytuj

Tworzenie procesów występuje w czterech podstawowych przypadkach :

  1. Inicjalizacja systemu.
  2. Uruchomienie wywołania systemowego tworzącego proces przez działający proces.
  3. Żądanie użytkownika utworzenia nowego procesu.
  4. Zainicjowanie zadania wsadowego.

W systemach zgodnych ze standardem POSIX funkcją, która odpowiedzialna jest za tworzenie nowego procesu jest fork. Natomiast w systemach z rodziny Windows NT odpowiedzialna za to będzie funkcja CreateProcess.

Usuwanie procesówEdytuj

Jest kilka sytuacji, w których może dojść do zakończenia procesu:

  1. Normalne zakończenie pracy (dobrowolne).
  2. Zakończenie pracy w wyniku błędu (dobrowolne).
  3. Błąd krytyczny (przymusowe).
  4. Zniszczenie przez inny proces (przymusowe).

Standard POSIX definiuje operacje: exit, abort, kill.

Interfejs Win32 definiuje natomiast: ExitProcess, TerminateProcess.

Wątki Edytuj

Wykorzystanie wątkówEdytuj

Klasyczny model wątkówEdytuj

Wątki POSIXEdytuj

Źródła: man pthreads

Wątki C++11Edytuj

Źródła: c11 c++11

Wątki JavaEdytuj

Źródła: klasa Thread

Wątki Ada(Ewentualnie)Edytuj

Przystosowanie kodu jednowątkowego do obsługi wielu wątkówEdytuj

Komunikacja między procesami Edytuj

Race conditionEdytuj

Sekcje krytyczneEdytuj

Wzajemne wykluczanie z wykorzystaniem aktywnego oczekiwaniaEdytuj

sleep i wakeupEdytuj

SEMAFORYEdytuj

  • POSIX
  • C++
  • JAVA
  • ADA

MUTEXYEdytuj

  • POSIX
  • C++
  • JAVA
  • ADA

MONITORYEdytuj

  • POSIX
  • C++
  • JAVA
  • ADA

Przekazywanie komunikatówEdytuj

BarieryEdytuj

Szeregowanie Edytuj

Klasyczne problemy komunikacji między procesami Edytuj

Problem 5 filozofówEdytuj

Problem czytelników i pisarzyEdytuj