Transkrypcja
Powitanie i wstęp
No i tego… Mieliśmy się dzisiaj przywitać inaczej, a nie tam „Cześć, Wojtek. Cześć Michał”.
Czyli to już jest wyświechtane
Witaj, Wojciechu.
Witaj Michale, witamy na kanale. Jak się zrymowało, to chyba…
To jak się będziemy żegnać, to powiemy „Bywaj”.
„Bywaj”. Dobrze.
To już mamy wstawkę z Wiedźmaka z dyńki… No i skończyliśmy sobie ostatnio na składowych tego tam systemu operacyjnego, znaczy zasygnalizowaliśmy, że są jakieś.
Tak, bo kontynuujemy systemy.
O te. Z tych książeczek.
Tak, z tych tutaj dwóch cegiełek, które leżą przed nami. Mamy składowe systemu
Czyli z czego się składają…
Procesy i wątki w systemie
…systemy?
Systemy. Tak jak już powiedzieliśmy w poprzednim odcinku, procesor jest tego, żeby procoesować procesy. Było bardzo zgrabne stwierdzenie.
Ma to sens.
Ma to sens. I te procesy są zwane zadaniami. Czasami to może tak w takich starszych ujęciach, bo systemy ogólnie – później o podziale też powiemy – ale przyjęło się dzielić na jedno- bądź wielozadaniowe. No i właśnie takim zadaniem w systemie jest proces, i on jeszcze może być podzielony na wątki. Tam zresztą proces i wątek to są takie dwa terminy, troszkę od siebie różniące się, jak można wywnioskować. Proces jest przeważnie nazywany tym cięższym, a wątek tym lżejszym. Nawet pojawiają się w literaturze czy gdzieś tam w użyciu w ogóle terminy: procesy lekkie, procesy ciężkie; wątki użytkownika, wątki jądra – tego typu rzeczy.
Przynależność wątków do procesów, mniej więcej przynajmniej w takich zastosowaniach naszych domowych, cywilnych tak, wygląda tak, że jeden proces i wiele wątków to jest taki najczęstszy model. Jeden proces, jeden wątek to jest właśnie dla takich systemów jednowątkowych albo wręcz jednowątkowych w ogóle, jak MS-DOS na przykład. To MS-DOS to nawet wstyd chyba systemem nazwać operacyjnym, ale trudno. No jak pradziadowie nazywali, no to już nie będziemy im tam przez szacunek dla białych głów, co nie? To my też możemy.
No i teraz są jeszcze takie zastosowania, że na przykład wątki mogą migrować pomiędzy procesami, ale to już są takie hardcory, że to – no nie będziemy na to strzępić języka, bo na pewno nie do takich zastosowań na co dzień w Jawce tego nie uświadczymy. W Jawce jest wszystko odizolowane i właśnie taka jest rola procesu, żeby on był strażnikiem zasobów. Właściwie proces jako ta cięższa jednostka, on ma ten cięższy kontekst – zaraz to jeszcze powiemy, z czego on się składa tak w zarysie bardzo – ale jego zadaniem jest pilnować, żeby zasoby były i żeby nikt w nich nie nabrudził.
Jeżeli on jest podzielony na więcej niż jeden wątek, może się dzielić, to my możemy tych wątków sobie tam tworzyć do woli, praktycznie. Znaczy, teoretycznie, a praktycznie do takiej cyferki, która jest limitem wątków. No tak, bo ciekawostka przyrodnicza: na przykład Jawka nam potrafi rzucić „out of memory error” nie z powodu skończenia pamięci, tylko wyczerpania puli wątków. Jeżeli mamy na przykład limit wątków ustawiony na 1024 i zrobimy 1025. wątek, to dostaniemy „out of memory error”, który nie będzie wynikał z przepełnienia sterty, tylko że za mało wątków, czy za dużo wątków jak na tą maszynę, za dużo, za dużo się dzieje, ma to sens. No bo po prostu te wątki, już to objaśnialiśmy, one współdzielą zasoby sprzętowe i głównie tutaj wiadomo, to co robi robotę, czyli procesor. Więc no nie możemy nadziubać tego nie wiadomo ile, bo koszt przełączania w ogóle tego zabije nam całe wszystko.
No tak, trzeba sobie powiedzieć, że w takim nawet normalnym laptopie to tych wątków jest dość dużo. Ja sobie przed nagraniem sprawdziłem, to obecnie u mnie chodzi 5000 wątków. O żesz ty! A u mnie… więc możemy sobie porównać. To jest u mnie chodzi, znaczy on mi tutaj wyświetla zadania: 297 – to będą grube procesy, i 2170 wątków. No to 5000, ale dużo. Tak naprawdę nie dzieje się… masz w tle właśnie? Nie mam, właśnie nie mam, nawet nie, nie mam Jawy, nie mam nawet. Mam Intela. Może troszeczkę tak, z 1000, pewnie też mam Intela. To nie wiem, to nie wiem skąd to się bierze, ale w każdym razie no Linux po prostu jest lepszy niż Windows.
Ale widać to skalowanie wątków na rdzeń, na procesor jest ten współczynnik dość duży, bo jeśli 5000 wątków można w miarę spokojnie obsłużyć, no to jest chyba całkiem dobry wynik i ten procesor sobie sprawnie radzi. Pewnie właśnie na takiej Amidze czy jakimś 286 to już by nie było tak gładko. Zaraz też będziemy mówić jeszcze o takim rysie historycznym, dlaczego by nie było tak gładko, ale tak można przeczuwać z tego, co już tutaj puściliśmy trochę farby, że no po prostu mniejsze częstotliwości taktowania niż teraz pozwalały na tyle aż szaleństwa.
A teraz mamy zegary gigaherc, gigaherc to jest… to są przy tych architekturach, przy tych zegarach, przy zwielokrotnieniu tego razy ilość rdzeni, razy ilość wątków sprzętowych. Bo tutaj te wątki sprzętowe to już omawialiśmy, to są takie logiczne procesory w obrębie jednego rdzenia procesora fizycznego. Czyli to wszystko miliardów tyk tego procesora tam, tam wychodzi. Jest taka miara: FLOPS – to jest ilość cykli procesora na sekundę. No i tutaj mówimy o gigaFLOPS, albo dziesiątkach gigaFLOPS. Później będą teraFLOPS. Teraz to duża ilość FLOPS. Kiedyś…
I tego, mimo że mamy tak dużo wątków, przepraszam, to one i tak tam sobie w większości siedzą po prostu po cichu w tle gdzieś tam jakieś tam wątki systemowe i tylko te aplikacyjne pewnie dochodzą do głosu raz na jakiś czas. Więc no procesor spokojnie sobie z tym radzi. A jak sobie nie radzi, no to nam w Task Managerze tam podskakuje na 100% i wszystko zamula, zaczyna strasznie szumieć, jak się dotknie tego. O tu to się robi gorąco w palec. No i takie tam ciekawostki z tego się mogą porobić, a później się wszystko unormuje i albo upadnie i po resecie już mamy znowu mniej wątków. Tak, tak, i znowu, znowu rosną. Ale no tak, działa to dość sprawnie i rzeczywiście ewolucja z tych, z tych pierwszych rozwiązań do stanu obecnego jest niesamowita. No i dzięki temu zawdzięczamy tę jednoczesną pracę wszystkiego płynną i nieprzerwaną.
A to wszystko jest iluzja, bo to jest multipleksowanie właśnie. Oczywiście, że tak, ale ta iluzja jednak robi robotę. Robi robotę. A jak to się dzieje, że ona robi robotę? Otóż właśnie taki proces ma swój blok kontrolny procesu. To jest taka struktura danych, która przechowuje wszystkie informacje niezbędne do tego, żeby można było w ogóle proces uruchamiać i przełączać. Czyli jak go tworzymy, dostaje identyfikator, dostaje swoją maszynę stanu, która mówi, czy on jest aktualnie wykonywany, czy oczekuje na coś. To zależnie od modelu procesu, od systemu, te diagramy stanu wyglądają tam troszkę różnie, bo mają albo więcej, albo mniej tych przejść. Na przykład taki Androidowy ma troszkę więcej zdaje się niż w Linuksie, bo w Linuksie nie trzeba aż takich dziwactw. Ale przykład: proces, jeżeli nie jest w stanie „run”, to jest jakiś tam „ID” albo jakiś wstrzymany, albo na przykład czeka na… i to wszystko może mieć odzwierciedlenie w tej maszynie stanu. Natomiast aktualny stan procesu jest zapisany w proces control block – w tym bloku kontrolnym procesu, po naszemu mówiąc – w polu stan.
Proces też ma priorytet, żeby było wiadomo, że no nie wolno głodzić tego, co od 7 lat tam już czeka rok, tylko niech wreszcie się wykona, się doczeka. Licznik programu ma, czyli wskazanie na kolejną komórkę z pamięci programu, którą należy wykonać, wykonując program. Po prostu, jak będziemy za chwilę mówić, wrócimy do procesorów troszkę, to, to, to się tam jeszcze rozjaśni. Ma wskaźniki pamięci na wszystkie obszary pamięci, jakimi tam musi zarządzać. Będzie to pamięć dynamiczna, jakaś tam statyczna, pamięć kodu. Jeżeli mówimy o procesie jednowątkowym, no to będzie też od razu, będą to dane tego wątku, czyli na przykład jego stos, dane kontekstu tego procesu, co sprowadza się do zrzutu po prostu z rejestrów procesora. Stan wejścia i wyjścia, czyli tych wszystkich operacji, które tam gdzieś wykonujemy na urządzeniach jakichś tam zewnętrznych. No i jeszcze tak dla księgowych – informacje rozliczeniowe, czyli co ile kosztowało, jakie podatki. Wiadomo, tak naprawdę to, to tutaj znajdują się dane, jakieś tam takie statystyczne, zbierane po prostu z wykonania tego, co wykonujemy, i później one są dostępne w jakiś tam miernikach, takich pokazujących nam zużycie procesora. W sensie no, ogólnie takie sprawdzamy sobie tak.
I właśnie w obrębie, jeżeli mamy procesy wielowątkowe i tworzymy sobie te wątki w ilości sztuk więcej niż jeden, to musimy… tylko troszkę na innym poziomie. Zaraz jeszcze powiemy, co to jest właściwie wątek, nie? I wątki mają coś takiego jak blok kontrolny wątku. Tam są troszkę zdublowane informacje. Znaczy, to jest taki jakby podzbiór tego bloku kontrolnego procesu, bo musimy wiedzieć tam też o liczniku rozkazów, o pamięci. Tam jest też stan wątku. Nie jestem pewien, czy priorytety się obsługuje w wątkach. Gdyby ktoś kiedyś zaimplementował…
Na początku byłaby taka, że proces jest tą jednostką nadrzędną, która zajmuje się alokacją zasobów i pilnowaniem do nich dostępu, natomiast wątki już wykonują faktyczną pracę w obrębie tego procesu. Przy czym wątki widzą całą przestrzeń adresową swojego procesu, z którego się wywodzą. I tutaj pojawia się pierwsza taka zagwozdka: „A co by było, jakbyśmy nadpisali z jednego wątku to, co widzi drugi wątek?” To nic prostszego – odpalamy IDE, klepiemy w Jawce kilka wątków i sobie nadpisujemy i patrzymy, jakie krzaki wychodzą, nie? Tutaj dochodzimy do zagadnień związanych ze współbieżnością, z synchronizowaniem wątków – wszystko to, co ma współbieżność i wątki w nazwie, to taka czasem zmora. Zupełnie osobny temat, który pewnie gdzieś tam też poruszymy kiedyś, omawiając jakieś szczegółowe rzeczy i jak to też w Jawie jest zaimplementowane i właściwie nie tylko w Jawie, bo to tego typu rzeczy polecam sobie wylać to też z tym związek, więc jest temat.
Ale generalnie tak, no tutaj wątki między sobą – no musimy synchronizować, bo inaczej będzie kiszka, ponieważ one współdzielą zasoby swojego macierzystego procesu. Natomiast procesy są na tyle już fajne – ale to też i to właśnie nadaje im tej ciężkości, można by tak to powiedzieć – że one już nie za bardzo są uprawnione do tego, żeby zaglądać sobie przez ramię, czyli jak odpalamy jakiś jeden proces, to on nie widzi pamięci innego procesu. No i my to możemy zaobserwować w systemie na, no, dowolnym współczesnym – braku bezpośredniej, łatwej komunikacji między jednym a drugim. To znaczy, komunikacja łatwa jest, bo system nam ją umożliwia, ale to nie dzieje się tak po prostu przez czytanie i pisanie do pamięci obok. Tylko na przykład nie wiem, żeby przenieść dane z jednego programu do drugiego, wykorzystujemy dodatkowe narzędzie jako schowek, nie? Jak na przykład schowek, czy chociażby pliki, czy coś tam. Oczywiście można tworzyć kolejki, jakieś potoki, czy coś, czy też inne wynalazki, które nam pozwolą po prostu transferować dane pomiędzy procesami, ale nie możemy tego zrobić bezpośrednio, zaglądając do procesu obok, bo izolacja jest podstawą. Też będziemy wspominać gdzieś tam później.
Więc to była właśnie taka różnica między tymi rzeczami i też zarys tego, co, co właściwie jest tą całą siłą napędową naszego przetwarzania, nie? Bo cała, cała praca dzieje się właśnie w procesach i wątkach. No i teraz jak to się dzieje – trzeba by było przytoczyć szybki rys architektoniczny z „Architektury komputerów, część pierwsza”, wykład dla pierwszego roku. Szybki, szybki taki tam był semestr.
Krótka historia mikroprocesorów
Może od historii zacznijmy, bo wspomnieliśmy ostatnio, że nie zapamiętaliśmy daty z tego wykładu właśnie, kiedy pierwszy był mikroprocesor. Ta data to jest 1971, kiedy to Intel wypuścił swoje 4004. I to był czterobitowy procesor. Po co więcej na początek? Ale to nie był pierwszy procesor, jak się okazuje, bo pod koniec lat… ale nikomu nie wolno mówić, co nie? To znaczy, wolno od 1998 roku. A bo tu mamy literówkę, przepraszam. 98 miało być, a tu mamy ktoś wpisał 9…
Ten 88 dla takiej fajnej jednostki, która się nazywa Centralą Aerometryczną Ziomale, zbudowali 20-bitowy procesor w technologii potokowej pod koniec lat 60. Więc ja nie wiem, czy to nie zalatuje jakąś Strefą 51, czy coś. No jak na tamte czasy 20 bitów, to rzeczywiście rozmiar słowa to było dość dużo. 20 bitów i potoki, tak, tak. No ten czterobitowy pierwszy to, to, to, no pierwszy był czterobitowy, więc widać, że to jest… Co się dziwi, że ich te myśliwce tak dobrze latają.
A wcześniej to warto też wiedzieć, że ten mikroprocesor, ten pierwszy, to on tak naprawdę stał się tym mikroprocesorem, bo zintegrował rzeczy, które wcześniej były rozrzucone gdzieś tam w tej maszynie. I dlatego to jeszcze nie nazywało się jako Centralna Jednostka, ponieważ wcześniej to było dużo różnych układów i ciężko było wskazać tak naprawdę, który jest centralny, które jest centralne, bo to było wszystko w różnych miejscach. Dosłownie nie była płyta główna, tylko gdzieś tam jakiś taki mechanizm analogowy, można powiedzieć z dzisiejszego punktu widzenia. Natomiast właśnie ten początek lat 70. to jest początek tej ery integracji już właśnie wszystkich elementów. Ady Lovelace już istniały, musiały istnieć, żeby w ogóle można było coś takiego zrobić, nie? Tylko właśnie te jednostki procesu, one były wtedy no, musiały być jeszcze zrealizowane na więcej niż jednym układzie i, i tutaj przełom Intel zrobił, proponując upchanie tego do jednej kostki.
Powstała z tego taka mała kostka, która później ewoluowała do wersji 8086, 8-bitowej. Później było 80286, 16-bitowe. 386 – 32-bitowe. No i od 486 to już tak naprawdę się zaczęła zabawa w świecie pecetów i ta końcówka właśnie tej, tej serii produktowej 86 stała się de facto synonimem zestawu instrukcji. Mimo że jakby zestaw instrukcji jest cały czas poszerzany przez no, jednak rozszerzenie tego standardu, ale właśnie końcówka ta 86 stała się no, jakby synonimem tak. I żeby było łatwo rozróżnić, to siostrzaną architekturę, którą tam AMD zaproponował, nazywamy 64. No tak, no bo tutaj mamy architekturę 86, właściwie X86, to się przyjęło, nie? A tam architektura 64. Ona ma coś, jakiś ten, jakąś literkę? No nie wiem nawet. Ale tak czy siak no to jest, jest, że tak powiem, chy… AMD64 to się w ogóle tak nazywa. Znaczy w ogóle w tych, w jakiś tam pakietach Linuksowych przynajmniej jest takie rozróżnienie. Musi coś własnego mieć, żeby jednak się wyróżnić. No właśnie, żeby stać się tym synonimem. Bo jeśli produkt jest na tyle popularny, że synonim nazwy czy kawałka nazwy staje się de facto symbolem całej linii, no to znaczy, że to jest sukces komercyjny.
Tak, ale tutaj małą szpileczkę. Natomiast żeby Workbench mógł hulać na Amidze, to wystarczyło mieć procesor 6510. Na Amidze 500, nie? Bo konkurencyjną rodziną do rodziny 86, a później AMD, była, znaczy nawet się nie doczekała także AMD, to już było po fakcie, ale była rodzina 65 tysięcy Motoroli. I to były wszystkie procki te takie cudowne pchane właśnie do Komodorek małych, do małych Atari, bo właśnie co ciekawe, na przykład ten 8008 on był w ZX Spectrum i w troszkę ulepszonym Z80, to jest ten taki podstawowy, nie? A Z81 to jest taki troszkę bardziej wypasiony, on tam miał wyższy zegar i w ogóle. Widać, że jak to u zarania standardów było cała masa i tak naprawdę dopiero czekaliśmy na, na wykształcenie się jakiegoś upadku niektórych. Upadniemy tutaj, tutaj jakiś Jacek ktoś musiał przegrać, ktoś musiał przegrać, żeby wygrać. My mamy te Inteley, AMD i praktycznie to są tylko liczące się procesory, które nam procesu… ale jeszcze tu właśnie nostalgia nakazuje przypomnieć te z rodziny 65 tys. i właśnie te, które Motorola pchała do Amigi. No a Atari też podobnie, bo wydaje mi się, że seria ST chyba maksymalnie miała procesor 03. Bo chyba taka była numeracja. 6510 to była ta rzecz mała w Amidze 500, a później chyba zero dopisali jeszcze i już były pięciocyfrowe. Aż tak nie śledziłem.
65020 to była jednostka podstawowa w Amidze 1200. Na Amidze 1200 w ogóle Workbench śmigał, tylko w starszej wersji ten, ten lepszy. Nawet ładniejszy graficznie, w sensie już taki, który mógł konkurować z Windowsem pod względem grafiki, zwłaszcza jak się go zapodało na rozdzielczości wyższej jak na Amigę, to tam 640 na 480 akurat rozdzielczość, to wtedy to wyglądało cudownie jak na tamte czasy. A jak to jeszcze wylądowało na procesorze 68030 albo, albo 40, no to już wtedy miało kopa takiego, że taki 486 się tam chował.
No, no i teraz tak, to z historii tyle wiadomo. A jeszcze w Makówkach ta seria, i która wyewoluowała w to, co mamy teraz. I ten klasyczny Mac OS przeszedł w OS X, macOS. Dojechał do wersji 9 coś i później wpadli na pomysł, że 10 podniosą do, tylko zastąpią Xem. OS X zrobili, na początku jeszcze w ogóle także tak marketingowo wyprodukowali takie małe medelki.
Wykonywanie instrukcji przez procesor i system przerwań
No i teraz tak, mamy taki procesor. Czy on będzie ten… on będzie musiał przeprocesować… musi być zdolny do wykonywania instrukcji. Model wykonywania instrukcji, niezależnie już w ogóle od procesora, zawsze jest taki sam i zawsze go można schematycznie – wiadomo, że będą modele prostsze i bardziej skomplikowane – ale schematycznie go zawsze możemy przedstawić nawet w postaci dwóch takich bloczków, gdzie jednym z bloczków jest pobranie instrukcji, a drugim jest wykonanie.
Pobranie instrukcji skutkuje załadowaniem bieżącej instrukcji wskazywanej przez rejestr programu. On się nazywa licznikiem programu – program counter. I to, co on pokazuje w pamięci, to jest ta instrukcja następna do pobrania. Więc procesor ją pobiera i teraz w najprostszym modelu, jeżeli mamy instrukcję o takim samym rozmiarze, po prostu inkrementuje ten licznik o jeden, w sensie przeskakuje komórkę czy też długość instrukcji, żeby można było wskazywać na kolejną. A w takich bardziej skomplikowanych i rzeczywistych zastosowaniach instrukcje różnią się długością czasami, więc no wypada sobie ustawić, zależnie od instrukcji, na kolejną instrukcję, ale procesor doskonale potrafi sobie to zrobić. Więc on pobiera instrukcję i przestawia licznik na następną instrukcję, co mu się przyda w przypadku przerwania na przykład.
Natomiast ta instrukcja trafia później do jednostki wykonawczej i jest wykonywana. Instrukcje są przeróżne, jest ich bardzo dużo. Będzie jeszcze więcej, bo cały czas ich przybywa, ale już nawet te, co są, to potrafią wykonywać operacje arytmetyczne, logiczne, potrafią podejmować decyzje bazując na stanie rejestrów procesora, potrafią przepychać pamięć pomiędzy rejestrami a pamięcią, właśnie w sensie przepychać zawartość powiedzmy tych rejestrów do pamięci, wartość pamięci do rejestru wrzucać. Przy czym mają jeszcze swoją pamięć podręczną, więc potrafią sobie ładować tą pamięć, z niej tam korzystać. No i jeszcze pewnie z milion różnych rzeczy potrafią robić.
Czyli to są takie podstawowe „building blocki”, z których korzystamy później na już na takim przy językach wyższego poziomu. Tak naprawdę to są takie minimalne właśnie klocki, z których atomy takie, z których się nasze programy składają. Bo gdybyśmy chcieli sobie faktycznie tak atomowo to programować, to służą do tego asemblery. Tak, oczywiście nie poleca się w dzisiejszych czasach pisać programów w asemblerze, tym bardziej że procesory mogą się obrazić i w ogóle na przykład sobie zmienić kolejność instrukcji takie, w sensie względem tego kodu, który my im zaproponujemy. Bo myślę, że my sami moglibyśmy się obrazić, tworząc najprostszego „cuda” w asemblerze. Nie polecam, to chyba już nie te czasy, nie te złożoności programów, żeby by się było cofnąć do lat 90. i tam sobie wtedy pokodować i wtedy życie było prostsze i w ogóle świat był prostszy i wszystko było prostsze.
Cokolwiek będziemy narzekać na skomplikowanie i kolejne warstwy abstrakcji, no to w tym wypadku to jest chyba zmiana na lepsze, bo inaczej byśmy wciąż przepychali te rejestry. No ale to właśnie już w tamtych czasach wymyślono, że na co to tak tymi mnemonikami? Bo właśnie taka instrukcja nazywa się mnemoniką. Po co operować ich dziesiątkami? Jak można na przykład w jednej linii C zawrzeć taki blok na przykład? Więc powstały języki wysokiego poziomu, które nas od tego odciążają, powstały też kompilatory. No ale to jest całkiem inna bajka i jak może kiedyś się do niej przymierzymy, to wtedy coś tam powiemy więcej, jak to się dzieje.
W każdym razie, no to, to, to, co autor miał na myśli, nasz programista, musi zostać przetłumaczone właśnie na ten język najniższego poziomu po to, żeby mogło to trafić dokładnie w takim formacie, jak architektura procesora wymaga, zgodnie z jego instrukcjami, z jego zbiorem instrukcji, do pamięci programu po to, żeby on mógł to sobie odczytać. No to sobie odczytuje właśnie jedna po drugiej i wykonuje. I takie dwa bloczki podstawowe to by była taka totalna podstawa w ogóle procesowania.
Ale jeszcze wymyślono system przerwań, więc tutaj możemy dorysować trzeci bloczek sobie na końcu. I jeżeli ten system przerwań jest wyłączony, to po prostu nie bierze udziału w całym cyklu rozkazu. A jeśli jest włączony, to po wykonaniu instrukcji procesor sprawdza, czy zgłoszono przerwanie. I te przerwania są bardzo różnorakich źródeł i powodowane właśnie różnymi sytuacjami, ale możemy tak, możemy właśnie w taki sposób, możemy je podzielić na, na prościej, że jeżeli coś dzieje się w programie, w sensie najczęściej to będzie poprzednia instrukcja właśnie, która się dopiero co wykonała, ona nam może zgłosić jakieś programowe przerwanie typu na przykład przepełnienie wartości albo niedobór wartości przy operacjach arytmetycznych, jakieś tam dzielenie przez zero i takie tam. W ogólności wyjątek, wyjątek. Taki wyjątek. Tak właśnie, wyjątek przetwarzania.
Natomiast przerwanie sprzętowe w ogólności to będzie zdarzenie zgłoszone gdzieś tam przez sprzęt z okolicy albo przez sam procesor, bo na przykład procesor ma jakiś swój czasomierz. I ten czasomierz to jest taka najniższa jednostka, najniższego poziomu jednostka zarządzająca czasem, dzięki czemu możemy w ogóle mówić o jakichkolwiek schedulerach w Springu na przykład. Gdyby tego nie było, nie moglibyśmy, znaczy no, moglibyśmy na upartego to emulować, ale byłoby to wysoce nieefektywne. Więc dużo lepiej jest opierać tego typu w ogóle, oprzeć pojęcie zegara systemowego na tym zegarze, na tym czasomierzu w procesorze, bo jak tam się dzieje gigaherc, to, to mamy w miarę precyzję, żeby to mogło działać jakoś sensownie.
To też może warto powiedzieć, że alternatywą dla przerwań jest polling, bo w przypadku pollingu to, ale to się wiąże z aktywnym czekaniem. Niestety, to się wiąże z aktywnym czekaniem, czyli co pewien interwał system czy pewien komponent poluje o status, czy to aplikacji, czy jakiegoś zainteresowanego innego komponentu. Natomiast przerwanie wypływa już od źródła i jakby z założeniem w takiej architekturze pecetowej było to, że generalnie jeśli system miałby teraz polować wątki, komponenty, czy w ogóle jakąś liczbę źródeł, większość z nich tak naprawdę w danym momencie zgłasza operacje: „Ja nic nie potrzebuję”, więc to byłoby nieustanne polowanie, bo to dzieje się bardzo szybko, bardzo często. Byłoby masa, tak, masa cykli procesora byłaby stracona na polowanie tak naprawdę bez zmiany statusu, bo większość tych, większość zainteresowanych jakby emiterów nic w tym momencie by nie potrzebowała. Natomiast przerwanie jest emitowane w momencie, kiedy faktycznie występuje. Więc mamy kiedy ktoś czegoś potrzebuje, kiedy ktoś czegoś potrzebuje. Więc mamy lepszą jakby taką czasową zależność, bo to jest rzeczywiście dzieje się w danym momencie wystąpienia zdarzenia, a po drugie dzieje się tylko w tych momentach, kiedy faktycznie ten, ten inicjator przerwania czy inicjator jest zainteresowany.
Natomiast ciekawym wątkiem jest też, znalazłem tak sobie też czytając, że przy na przykład obecnych technologiach w dyskach SSD to przerwania właśnie stają się wąskim gardłem ze względu właśnie na niesamowicie dużą przepustowość danych w nowych dyskach. I tam podobno już coraz bardziej też polling mógłby być lepszym rozwiązaniem właśnie ze względu na bardzo dużą tak. Powrót do klasycznych przewijaków taśm, nie? Powrót – to troszkę mamy początek i jedziemy. Troszkę tak: „Chcecie to bierzcie, nie to nie – zignorujcie, ale nie będziemy tu przerywać, bo szkoda czasu”. Tak, tak, tak. W ogóle polecam obejrzeć sobie jakiś filmik na YouTubie, jak są zbudowane dyski SSD i jak w ogóle, jak w ogóle działają, jak w ogóle są ułożone te komórki pamięci na sobie i w jakich wymiarach. I to jest fascynująca technologia. O tym nie wspomniałem, ale to naprawdę to jest właśnie ta fizyczność, nie? Tutaj ta fizyka na poziomie już subatomowym i wręcz niekiedy kwantowym, nie? To, to już ona decyduje o tych prędkościach. My tak naprawdę już teraz powoli docieramy do granicy sprzętu. Już tam nas straszą wprawdzie od lat 80., że do momentu będzie koniec i tyle. No i faktycznie zgodnie z prawem Moore’a o tym, że podwaja co ileś tam czasu wydajności, no dojechaliśmy teraz do tych wydajności giga. I jakoś dalej to nie chce iść, ale jeszcze nie wieszczący na horyzoncie gdzieś tam jakieś przetwarzanie kwantowe, ale mimo wszystko już teraz właśnie w takich architekturach w tych procesorach supernowoczesnych tych tak, no tych, które mamy tutaj w tych laptopach, nawet nie. Tam dochodzą prawdopodobnie już do głosu zjawiska no już na poziomie na pewno atomowym. Cząsteczkowe to już były dawno temu, a teraz, teraz już mamy coś takiego. No i tam gdzieś kiedyś wpadł mi w oko jakiś artykuł, gdzie były chyba eksperymenty ze światłem, w sensie procesory oparte na świetle, świetliste takie, nie? Bo no to już tak pewnie pogranicze tego przetwarzania kwantowego. No bo wiadomo, że taki elektron, zanim przebędzie drogę z punktu A do B, to mu chwilę schodzi. A schodzi mu dlatego, że ma masę, więc trzeba więcej energii na to. Natomiast foton, taki fajny gościu, można go tam przepychać dużo łatwiej. Bezkosztowo. Bezkosztowo. To chyba wszystko są zalety coraz większej miniaturyzacji. To sprawia, że czy to właśnie te dyski SSD, które też są coraz mniejsze, czy właśnie coraz lepsza litografia w procesorach – obecnie 13. generacja Inteli ma już 10 nanometr litografię. Więc to też sprawia, że możemy opakować coraz więcej tych ścieżek, gdzie jony mają tam się poruszać. To jest fascynująca dziedzina właśnie ta fizyka. Gdyby jej nie było, to nie byłoby procesorów, ale może wróćmy… właśnie tą fizykę wykorzystują. No i tutaj nam działają.
A wracając do samego systemu przerwań, to jeszcze w ogóle ci, co wymyślali system przerwań, to chyba byli pradziadowie tych, co wymyślali Reactive Manifesto. A właśnie usłyszałem fajne sformułowanie: „Stoimy na ramionach gigantów”, nie? Bo my jesteśmy, my czerpiemy z tych mądrości stworzonych przez naszych poprzedników. O, czasami nawet nie wiedząc o tym. Czasami tak. Ale dobrze jest sobie to uświadamiać i, i po prostu no, chociażby traktować tych poprzedników z należytym szacunkiem, nie? Więc stojąc na tych ramionach gigantów, mamy do dyspozycji takie narzędzia, że teraz na przykład możemy budować na nich nowe rzeczy. A tutaj znowuż wracamy do technologii z lat 70., nawet ten procesor tajny w F-14 z lat 60. z końcówki. To, to też to, to pokazuje, że te same, te same zjawiska, tylko na poziomie daleko innym niż w naszych współczesnych reaktywnych aplikacjach, występowały właśnie w sprzęcie i dalej występują cały czas. Nie?
No tak, bo takie przerwanie to jest nic innego jak zdarzenia asynchroniczne. To jest właśnie odwrotność tego synchronicznego pollingu. I dzięki temu, że ono jest, my mamy zaoszczędzoną masę czasu tego procesora, który po prostu wykonuje swoje instrukcje i dopiero wyskakuje z bieżącego potoku rozkazów, kiedy się zdarzy stosowne przerwanie, o ile ono jest oczywiście odblokowane, nie? I bo, bo jeszcze są… miał być 13-minutowy wstęp, sorki, wyszedł 15, może plus i to jeszcze się nie skończył.
Ale systemy przerwań jeszcze mają określone maski, więc tam można, ponieważ tych przerwań można sobie naprodukować bardzo wiele, to, to, to dobrze jest też maskować się jakoś wybiórczo, jakoś tam hierarchicznie czy coś tam, nie? Więc w ogóle to jest całe to zagadnienie, to, to już jest też na solidne grube rozdziały w podobnych książkach tylko o sprzęcie. Tak, niemniej jednak no, jest czym tam zarządzać i z czego tą moc wykrzesać, nie? Tak jak się popatrzy na procesor współczesny, to, to jest niesamowicie skomplikowane urządzenie, które wręcz magią zalatuje czasami, a tak naprawdę wystarczą… Zaawansowana technologia jest nieodróżnialna od magii. No, tutaj jesteśmy już na granicy tej nieodróżnialności dla zwykłego człowieka, bo tak naprawdę tak, już nawet mając stare procesory w garści, to nie byliśmy w stanie, nie bylibyśmy w stanie prześledzić ich toku myślenia, oczywiście, po prostu one no, ze względu na to, że natura naszego procesowania jest inaczej częstotliwościowa. No my mamy bardziej równoległe procesory, troszkę wolniejsze, ale równoległe i niemniej wydajne, co też warto o tym wspomnieć.
Przerwania a stany procesora
Dobra, czyli mamy procesory, które wykonują sobie ten kodzik i teraz to się nam pięknie łączy na przykład to, to wszystko, co do tej pory powiedzieliśmy, plus dyrdymały z tym właśnie z tym stanem procesu i z licznikiem rozkazów, które siedzą w process control block albo w kontrolnym bloku wątku. Te same rzeczy będą się działy w wątku. Może już teraz pomińmy ten proces control block całkiem i skupmy się tylko na wątku. Ten wątek jak na przykład się wykonuje i przychodzi jakieś przerwanie sprzętowe, czy musimy z niego wyskoczyć, więc trzeba zapisać ten stan tego właśnie licznika programu, załadować do rejestru licznika programu nowy adres obsługi tego przerwania czy tego wyjątku. Już w ogólności de facto wtedy procesor wykonuje skok do innego obszaru pamięci programu, wykonuje tą podprogram obsługi tego przerwania. Jak ją skończy, to mówi „skończyłem” i wraca do tego, w sensie ta procedura się kończy. Więc mechanizm zakańczający tą procedurę ładuje ostatni adres zapisany i do tego się przydaje stos.
Stos wywołań i adresowanie pamięci
No bo te właśnie adresy odkładamy na stosie kolejnych wywołań. Więc ściągamy ze stosu ten adres powrotu i siup – wracamy dokładnie w to miejsce, na którym skończyliśmy, tylko komórkę dalej. Czyli nie wracamy do instrukcji, z której wyskakiwaliśmy, a do następnej, bo tą już wykonaliśmy. No i tak to właściwie działa. Co tu dodać, że te adresy i te komórki to wszystko to jest pewne logiczne mapowanie, bo to system odpowiada za faktyczne fizyczne rozmieszczenie. To wszystko może być rozczłonkowane w pamięci dowolnie, tylko właśnie system musi wiedzieć, gdzie to jest. Tak, tak. Więc to tak naprawdę system dopiero on wie, gdzie to wrzucić faktycznie fizycznie w pamięć, a my się też nie musimy tym przejmować, jakby samą topologią pamięci, rozmieszczeniem tego, bo to już jest jakby…
Rola pamięci operacyjnej (RAM)
Dokładnie, to teraz może właśnie do tego. Rolę procesora mamy mniej więcej omówioną, czyli ta rola wykonawcy kodu, a teraz ten sam, ten kod leży właśnie w pamięci. To może o roli pamięci powiedzmy.
Istnieje takie pojęcie pamięci jak RAM, czyli Random Access Memory, i to się tłumaczy na nasze pamięć o dostępie swobodnym. Tak naprawdę, jakby to przetłumaczyć literalnie, to była pamięć o dostępie przypadkowym. Było wycwane. No ciekawe, czemu tak to nazwali, może tam po prostu słowo „random” ma jakieś takie bardziej znaczenie niż ta przypadkowość. Ale chodzi o to, że mamy dostęp, znaczy procesor ma dostęp, czy układy w ogóle w naszym systemie sprzętowe, układy w naszym systemie sprzętowym. No mówimy o systemach operacyjnych, które są systemami softwarowymi, ale one pracują na systemach sprzętowych. Słowo „system” będzie się pojawiać i w tym, i w tym kontekście. No i teraz pojawia się w kontekście sprzętowym: wszystkie te układy, które muszą mieć dostęp do pamięci, a to oprócz procesora oczywiście jest cała masa innych. Bo oprócz procesorów – bo systemy są zazwyczaj wieloprocesorowe – mamy jeszcze jakieś tam sterowniki pamięci, na przykład właśnie sterowniki układu wejścia-wyjścia. One wszystkie muszą pisać do pamięci, muszą mieć i czytać z niej, muszą mieć dostęp.
Na przykład układ zaciągania kolejnych linii cache’a, wypełniania cache’a w procesorze, to jest też układ, który pracuje niezależnie od tej jednostki przeliczającej. Procesor ładuje sobie z pamięci po cichu kolejne instrukcje tak, żeby mieć je pod ręką, bo ta pamięć, mimo tego że jest o dostępie swobodnym, jest o rząd wielkości… Może teraz to już nie o jakieś grube rzędy. Kiedyś drzewiej to bywało, że ona potrafiła być tysiąc razy wolniejsza na przykład od samego procesora, czyli dostęp na przykład do komórki pamięci powodował marnotrawienie tysiąca cykli lub więcej, nie? To kiedyś nawet czasami to dochodziło do milionów cykli. Więc wpadnięto na pomysł buforowania. No i właśnie te wszystkie cache, które procesor ma na pokładzie, do których ma dostęp błyskawicznie, tak porównywalnie, już może o mniejsze rzędy wielkości, ale z grubsza porównywalnie do w ogóle szybkości pracy na rejestrach – gdzie praca na rejestrach to jest ta praca z maksymalną szybkością procesora właśnie w cyklu rozkazowym – one muszą być zasilane tymi danymi, w sensie tym kodem programu, żeby to wszystko się zgrabnie kręciło. Bo jak chcemy wycisnąć siódme poty z procesora, to on nie może czekać, on zawsze musi mieć coś do roboty.
Więc rolą pamięci takiej swobodnej i tych wszystkich układów współpracujących jest dostarczać kod programu i dane do procesowania dla procesora. Natomiast mamy jeszcze pamięć nieulotną, jeżeli zgasimy zasilanie, jej zawartość zniknie. Pamięć nieulotna to jest wszelkiej maści pamięć zapisywalna trwale, począwszy od takich wczesnych ROM-ów, zwanych flashami jeszcze, ROM-ów niezapisywalnych na przykład. Bo, bo tak weźmy tutaj nieśmiertelny przykład z Amigi: tam trzeba było mieć Kickstart w odpowiedniej wersji, żeby w ogóle system można było zainstalować. No i trzeba było mieć taką kostkę z cyferką, trzeba było mieć wtykę tą tam, gdzie trzeba. I jak się podmieniło tą kostkę na wyższą, to można było mieć wyższy system, w sensie można było zainstalować, bo to był taki ten, ta, ta najbardziej korowa rzecz w tym systemie.
Właśnie tak, czyli to był w takiej definicji to, co wcześniej mówiliśmy, to bardziej chyba definicja takiego firmware’u, bo to jest też różnica pomiędzy systemem operacyjnym a firmware’em, że firmware najczęściej jest przypięty do jakiegoś elementu hardware’u. Są właśnie zaszyte najbardziej elementarne algorytmy, na przykład dostępu do tej pamięci. Tak więc system operacyjny możemy sobie zmienić, jakoś go tam zupgradować, natomiast firmware już ciężej to zrobić. Można zupdatować, czy coś, ale to już najczęściej… Oczywiście w takich komputerach jak teraz mamy, oczywiście ten firmware też możemy updatować, bo jak przychodzi raz na jakiś czas Windows, to on potrafi tam przypomnieć, że ten akurat konkretny jest groźniejszy, bo będziemy BIOS-a przeczyszczać, przeinstalować i wtedy bronicie tam w ogóle wyłączyć zasilanie, co nie? Jako taki pierwszy, pierwszy punkt wejścia. To się rozwija na Basic Input Output System. Właśnie doskonale opisuje. Cozy Amigi był BIOS-em takim, jak teraz mamy w… Więc pamięć ROM, wracając już do tematu znowuż. Pamięć ROM na w takich najbardziej podstawowych wersjach i starszych ona była niekowalna i w ogóle nie można jej było modyfikować w locie. Później się zaczęły pojawiać już takie modyfikowalne pamięci, ale wspólną ich cechą jest to, że ona jak jest zapisana, to przetrwa wyłączenie zasilania. Oczywiście jest jeszcze taki miks pamięci ulotnej, podtrzymywanej bateryjnie. Jak się wyciągnie bateryjkę, to wtedy gaśnie. No ale to tym się nie będziemy zajmować.
No i cache procesora to już mniej więcej omówiliśmy. Aha, do pamięci nieulotnej to właśnie dyski należą, począwszy od oryginalnych dysków, które jeszcze miały talerze, które się tam kręciły i były podatne na uszkodzenia, po te współczesne SSD, które praktycznie są nie do zajechania. No chyba że przekroczymy ilość cykli zapisu i odczytu, bo jednak one nie są takie do zajechania. Są trochę. Są w jakiś takich klastrach serwerowych. To pewnie trzeba, jak kiedyś chodzili z koszykiem lamp, to teraz chodzą z koszykiem dysków. To z każdą jakby generacją tych dysków oczywiście te parametry liczby cykli zapisu i odczytu są poprawiane i tak naprawdę do cywilnego użytku, tak jak sobie używamy na co dzień, no to, to chyba nie osiągniemy tego, tego, tego, tego, tego parametru, żeby, żeby to się jakoś strasznie na wydajność spadła. Ale rzeczywiście no, jest ten, jest ten, ten taki element pewnej degeneracji komórek zapisu. To są wartości liczone chyba w dziesiątkach tysięcy cykli, jeśli nie w milionach. Tak, to są bardzo dużo. Albo w dziesiątkach milionów być może teraz, bo dziesiątki tysięcy to były przewidziane dla takich zwykłych, prostych pamięci flash. Które projekt…
Intel ci się przebuduje trzy razy, zrobisz „clean” i już będziesz miał… Przepraszam, emocje, bo zaraz przejdziemy do tego, do zarządzania pamięcią i że wcale tak ta Jawka jednak nie zajedzie nam dysku tak szybko. No oczywiście, jak będziemy kodować po nocach, to zajedziemy siebie. Siebie też, Jawkę i dysk. No i na monitorze nam się wypali, tak jak kiedyś bywało na starych CRT monitorach, że po zgaszeniu monitora dalej był ten sam DOS. Bo na nowych OLEDach no, no chyba… Czyli wszystko wraca. OLEDy się wypalają. OLEDy się wypalają, no bo to są diody organiczne, więc mamy efekt wypalania. Co prawda w nowych, w nowych modelach oczywiście to już też jest pewnie coraz mniej zauważalne, ale tak. Jeśli będziemy mieli ciągły element, dlatego właśnie wygaszacze powstały. Wygaszacze, no to to jest inna rzecz, ale no ciągłe, ciągłe, ciągłe wyświetlanie pewnych elementów jakiegoś interfejsu czy czegoś musi powodować. Że lepiej wyświetlać jednak na tych ekranach ciągle zmieniające się gry, bo przynajmniej się ekrany nie wypalą. Tak, dlatego lepiej grać kilka godzin w różne gry niż 10 godzin w jedną, lub siedzieć w DOS-ie 10 godzin. Albo siadać.
Zarządzanie procesami i wątkami
No i właśnie, czyli tak: procesor mamy, pamięć mamy, system przerwań w procesorze też już omówiliśmy. No i teraz możemy już wyjść wyżej na element powiedzmy taki, no ten aspekt systemu, który zarządza różnymi jego częściami. I tutaj na chyba najbardziej… no wypada zacząć od tego zarządzania procesami i wątkami, bo to jest właśnie najważniejsze. Oczywiście to nie istnieje bez zarządzania pamięcią, ale no ta jednostka pracy jest przyjęta za coś ważniejszego.
I tutaj mamy do rozważenia przede wszystkim algorytmy planowania takich zadań. Nie? Bo zaczęliśmy opowiastkę naszą od systemów jednozadaniowych, gdzie algorytm planowania zadań to było: wrzucamy do bufora i czekamy, aż się wykona. Jak zapchaliśmy bufor, znaczy powinniśmy zapychać ten bufor tak, żeby cały czas coś w nim było, żeby procesor nam tutaj nie czekał i, i się dolar nie marnował. Jeszcze w tam starych jakichś mainframe’ach amerykańskich w dodatku, chociaż na naszych Odrach to było pewnie podobnie. No jeszcze, jeszcze działały Odry kilkanaście lat temu i coś tam liczyły. Więc coś tam liczyły i ponoć nie były takie najgorsze, wręcz przeciwnie, a Elwro nasze to właśnie chyba nimi słynęło. Tak, tak, tak.
Więc jeżeli mamy prosty system wsadowy, to algorytm zarządzania procesem nie istnieje, bo jest jeden proces. Ten proces cały czas polega na wykonywaniu tego, co jest w tym buforze, nie? Kolejnych zadań. No ale jak już mamy system wielozadaniowy, no to mamy tych procesów więcej niż jeden, więc musimy teraz rozkminić, w jakiej kolejności mamy te procesy przełączać. Mamy blok kontrolny, już może już mamy kontekst procesu złapany, więc możemy sobie taki proces zatrzymać w dowolnym momencie jego wykonania. On nie będzie o tym wiedział, jeżeli nie będzie oczywiście no program, który on tam ma, sprawdzał tych znaczników czasu. Kolejka wejdzie, ale dla niego stwarzamy iluzję pracy ciągłej, a jednak system musi je podmieniać na, na kolejne, nie? Więc no powstały różne algorytmy szeregowania zadań. To jest w ogóle taka klasa algorytmów dość skomplikowana, bo nie jest tak łatwo upchać zawsze wszystko do plecaka. Trzeba czasem pokombinować, ale daje się to zrobić.
Są takie na potrzeby systemów operacyjnych. Najprostszym i dość szeroko chyba wciąż stosowanym algorytmem jest Round Robin, czyli po kolei. Mamy taki pierścień złożony z tych procesów i po prostu go przekręcamy o jeden i zawsze ten kolejny nam wskakuje. No chyba że jest jakiś właśnie coś, coś ważniejszego o wyższym priorytecie, to wtedy po prostu to coś wskakuje na jednostkę czasu. I jeszcze kwestia jest, może właśnie dostania tej jednostki czasu, bo, bo coś ważniejszego może dostać to na dłużej, a jakiś taki zwykły proces, ten głodzony, to po prostu dostanie ochłapy. Tak, no i żeby uniknąć tego głodzenia, to jednak dobrze jest raz na jakiś czas to właśnie jest wniosek z tego eksperymentu, z tego znaleziska, jak tam po siedmiu latach znaleźli ten proces zagłodzony, biedny, już szkielet. To, to wpadnięciu unikamy zagłodzenia, bo w końcu ten proces stary dobije się już na sam szczyt, awansuje i będzie mógł być wykonany. Natomiast procesy młodsze, które dopiero zostały powołane do życia, nie będą podbijane w tym czasie, nie? Bo one muszą tam odczekać ileś tam, muszą się odpowiednio zestarzeć, żeby móc wziąć udział w tym, w tej zabawie.
Kolejnym ciekawym zagadnieniem przy zarządzaniu procesami są zakleszczenia. I tu jest taka fajna, zawsze przynajmniej w tamtej książce jest chyba właśnie nawiązanie do tego urzędu patentowego ze Stanów Zjednoczonych, gdzie… A nie, przepraszam, to, to zła anegdota mi się tutaj zmiksowała. Urząd Patentowy to, to jedno, a ten była taka anegdota właśnie o zakleszczeniach na przykładzie skrzyżowania linii kolejowych. Bo zanim wymyślono wiadukty, to tam po tych preriach rozkładali tak i w poprzek i było takie zagadnienie, gdzie chyba właśnie w tym, w jakimś podręczniku kolejarzy, czy gdzie… już nie pamiętam, i tak spaliłem, to już nieważne, co nie? Ale gdzieś tam w jakiejś mądrej książce było napisane, że jeżeli zdarzy się tak, że do tego samego węzła dojedzie więcej niż jeden pociąg, to każdy ma czekać, aż ten drugi przejedzie pierwszy. No i tutaj mamy klasyczny przykład, jak nie należy pisać podręczników dla kolejarzy, a także projektować algorytmów współbieżności.
To może stąd się wzięła ta amerykańska zasada skrzyżowań równoległych, że rusza ten, który podjechał pierwszy. Może z pociągiem jest podobnie. Może tak, może. Tylko jak to teraz wymaga pewnej takiej subtelności, bo jak się podjeżdża, to trzeba rzeczywiście tak określić, czy to w sumie ja podjechałem pierwszy, czy nie. No jak ktoś jest bardziej ambitny, to on zawsze podjeżdża pierwszy. Wydaje. No i ale zaskakująco się sprawdza ten nawet. Więc sprawdza. Ale w Indiach też mają zasadę poruszania się po skrzyżowaniach. Widziałem na YouTubie. Tak, tak. Bardzo płynnie się poruszają. To takie poruszanie współbieżne, jeden organizm. I jakoś tak rzadko im się coś poważnego tam dzieje, chociaż te ich pojazdy to chyba wymaga lat, lat praktyki i klaksonów dobrych. Zawsze jest tak okraszone takim dźwiękiem. Ale radzą sobie.
No więc istnieją algorytmy radzenia sobie z zakleszczeniami, czemuż by nie. No i one właśnie są zaimplementowane tutaj na poziomie troszkę systemu operacyjnego jako takiego. No bo mimo wszystko programowo możemy stłamsić dwa procesy tak, że się zakleszczą po prostu, nie? Zablokujemy jeden na drugim i koniec kropka. Ale system operacyjny ma taki mechanizm jak wywłaszczanie procesu. Bo dość szybko chyba dostrzeżono to zagadnienie, że jak niestety się zdarzy taka awaria, no bo to jest awaria w systemie, to po prostu trzeba ten zakleszczony, ten zablokowany proces wykopać aktualnie z kolejki. Trzeba też sobie dodać, że o ile większość z tych rzeczy rzeczywiście załatwia za nas system, w sensie za nas, za programistów, czyli nie musimy sobie przejmować się priorytetem czy głodzeniem, to zawsze dojdzie do skutków. Nie, ten Tomcat co tam był z lat 60. Oczywiście. Tak, tak. Nie ten, którym latał Tom Cruise. Natomiast no, jakimś F, jakimś tam… Już nie pomnę, którym. A nie, 16 nie, 16 to był ten. Nie pamiętam amerykański Orzeł.
W każdym bądź razie zakleszczenia niestety możemy sobie też sami spowodować w naszym programie. Więc tutaj z przyjemnością tutaj system, no nie zawsze nas, w sensie system operacyjny nie zawsze nas wspomoże, jeśli chodzi o zakleszczenia. Możemy sobie tak skonstruować nasze, nasze loki, że dojdzie nam do zakleszczenia, a cały system dalej, to jest też nie zablokujemy całego systemu. Oczywiście co było bardzo niefortunne, gdyby akurat nasza aplikacja prościutko wywaliła nam cały serwer. Ale no to jest akurat ten element, z którym jeszcze systemy nie radzą sobie na tyle, żeby poradzić z tym. To to zdjąć. Więc musimy jednak te zakleszczenia, jeśli chodzi o programowanie wielowątkowe, loki musimy sobie jednak… Myślę, że to jest doskonały materiał na naszą falę hejtu, którą obiecałem w poprzednim odcinku, jak tylko zdążymy w tym, a jak nie, to może za chwilę jeszcze. Utrzymaj tam dobry nastrój, zanim do tego dojdzie. W każdym razie zakleszczenia, tak jak mówisz, na poziomie programu jak najbardziej to możemy sobie zrobić w dowolnym momencie. No i tyle, no i systemu nie interesuje, co nasz program zrobił. Tak naprawdę zakleszczył się, siedzi sobie na tej samej instrukcji, czeka na nie wiadomo co. No to luz, to po prostu zwalnia cykle procesora. Prawdopodobnie tam się jakieś przerwania poustawiały. Do jutra na przykład. Lub tak. No mimo wiszenia, cały czas kawałek czasu te nasze wiszące wątki dostaną. No i będą tak sobie zgłaszać, że wiszą. Wiszą. Tak, jeszcze wiszę, dzięki, nara. Czekam, aż ten drugi przejedzie, nie? Tak.
No ale na poziomie już systemu, kiedy na przykład tak jak wspomnieliśmy, systemy nie obsługiwały wywłaszczania, to wątek sam musiał oddać sterowanie. Czyli znaczy proces, to jeszcze były te czasy, że jeszcze chyba za bardzo o wątkach się nie mówiło. Chociaż nie jestem pewien, czy, czy istnieją wielowątkowe systemy bez wywłaszczenia. Musiałbym znowu przewertować te dwie książki, a już nie mam siły, ciężkie są, kurka. Właśnie system bez wywłaszczania, czyli bez możliwości wykopania tego zakleszczonego czy w ogóle zepsutego procesu, wątku czy cokolwiek tam się dzieje, to dochodzimy do sytuacji, że jak mamy awarię w programie, to umiera nam cały system, koniec kropka. Nie? Po prostu zawiesiło się. Istnieją takie systemy. Przecież Windows tak robi. Już tak nie robi. No jeszcze robi trochę. Nie? Się zdarza. Kiedyś robił. Wczoraj koledze tak się porobiło, że tylko bluescreen. Komputer przysyłają to chyba 11. No nie wiem, pech, czy co. W każdym razie kiedyś Windows potrafił zrobić brzdęk albo nawet nie zdążyć i było niebiesko i finito. Potrafił się tak w ogóle zawiesić. Dobra, to zostawmy na falę hejtu.
Natomiast wywłaszczanie to jest taki fajny mechanizm, który wprowadzono, który po prostu, że planisty systemowego, to taki dany wątek potrafi nawet być ubity, nie? No i ciekawostka jest taka, że te wątki potrafią być w przeróżnych stanach. To zresztą wątki, procesy i w ogóle no, co, co tylko tam mamy w tym systemie. Bo na przykład w Linuksie widzimy czasami procesy Zombie. Nie w Windowsie nie zobaczymy, bo tam są skrzętnie ukrywane. Tam w ogóle ciężko coś zobaczyć, co jest nie pomyśli Billa. Ale w Linuksie wszystko widać jak na dłoni. I na przykład taki proces, który by uprzejmy się zawiesić, zostanie oflagowany jako Zombie, bo on po prostu nie odpowiada. Nie? I możemy go na przykład sobie usunąć już ręcznie albo może zostać wyczyszczony jak, jak ten, jak program w ogóle zamkniemy, nie? To program po sobie posprząta i wtedy znikają jego procesy. Także wywłaszczanie jest bardzo fajnym mechanizmem. Tak, tak. Mniejsze zło. Wiedźmin by się nie zgodził.
Czyli tak w ogólności nie ma co tam rozwlekać tego planowania dalej, bo można by wymyślać jakieś algorytmy, inne dyrdymały. To by było sedno tego zagadnienia: musimy zaplanować kolejność i w tej kolejności musimy je wykonać, ewentualnie zmienić kolejność, jeżeli zmieniają się warunki, na przykład priorytety.
Zarządzanie pamięcią
Dokładnie. No i teraz ten proces nasz czy wątek ma mieć dostęp do pamięci. Najchętniej by chciał z tej pamięci RAM sobie ciągnąć, bo tam mamy najfajniejsze rzeczy. Przeważnie jak mamy na dysku super fajne rzeczy, to najpierw ładujemy do RAM-u, a później z tego RAM-u ciągniemy do procesora. Bo mimo tego, że dyski SSD są takie fajne i szybkie, to jednak te pamięci RAM są jeszcze fajniejsze i szybsze, a procesor lubi najfajniejsze i najszybsze pamięci. Więc on jeszcze czasem lubi sobie to wszystko właśnie dociągnąć jeszcze do swojego cache’a, nie? Pośredniczą w tym wszystkie układy po drodze, jakie są, które go w to zasilają tak, żeby on już mógł się rozpędzić i sobie jechać.
No a już to tak jak wspomniałeś, sama zawartość tej pamięci RAM to już może być totalne, no z naszego punktu widzenia to mogą być totalne krzaki, ale to ma swoją strukturę. Bo każdy proces dostaje jakąś tam, jakiś wycinek tej pamięci, taki jaki sobie alokuje, lub do jakiego może. No może chcieć sobie sięgnąć, może dostać uprawnienie, nie? Dostaje sobie określone bloki pamięci. Te bloki siedzą w takich strukturach danych, które się nazywają stronami pamięci. Bo co to jest w ogóle adres pamięci? Co to jest w ogóle pamięć? O matko, którą mamy godzinę? Nic nie zdążymy. Chyba musimy bardziej do ogółu zejść.
Do ogółu. No więc mamy obsługę pamięci. Jest zrealizowana perfekcyjnie prawie. Dobra, nie. No trzeba powiedzieć o tym. Pamięć to jest taka, taki ciągły zbiór komórek, w których możemy coś zapisywać. Najczęściej one mają rozmiar słowa zgodnego z architekturą. Teraz mamy najbardziej popularną architekturę 64-bitową, więc te pamięci są też 64-bitowe. Jak się zgadza słowo tego i tamtego, to, to transfery są najfajniejsze. Nie? Tutaj też już się nam wcześniej pojawił taki motyw o wyrównywaniu pamięci, jak rozmawialiśmy o tam niuansach języków i tutaj właśnie dokładnie to ma zastosowanie. Bo wszystkie adresy muszą być podzielne przez długość tego słowa po to, żeby lądowały w kolejnych słowach. Wtedy te słowa są poszczególnymi wartościami, która wskazuje na odpowiedni numer tego słowa, tej komórki, to jest właśnie adres, który jest w C++ pointerem, a referencji jest tak dużo, że to się w niczym nie mieści. Trzeba to podzielić na strony. Dzielimy to na strony.
Zarządca pamięci… do tego zarządcy pamięci, w sensie zarządca procesów, rozmawia z zarządcą pamięci, mówi: „Daj mi tutaj ileś tam stron tego, bo ja tu muszę mieć gigabajt stertę, bo ja tu Java jestem”, co nie? I zarządca pamięci mówi: „Dobra, to masz tu swoją stertę, tylko ją szanuj”. Po czym proces rzuca „out of memory”, bo szanuj i nie fragmentuj, nie fragmentuj i zwalniaj pamięć, bo cały czas alokuje pamięć, nie zwalniając jej albo sporadycznie to robiąc. To mamy po prostu cały czas poszatkowane. Tak jak mamy defragmentację dysku, coraz, coraz mniej mamy takich dużych bloków, więc coraz ciężej jest tam zaalokować cokolwiek zmieścić. Więc jakby stąd wynika właśnie idea w ogóle śmiecenia czy, czy ogólnie też wyjątków z brakiem pamięci, bo cały czas mamy zajętość.
Właśnie idea stron to też tutaj przyszła z pomocą, bo to był taki… o ile na przykład to, o czym wspomniałeś, to jest już takie jawne w ogóle zajrzenie do C, ogólnie do mechanizmu zarządzania pamięcią w językach zarządzanych, to jak mamy język niezarządzany, na przykład C++ albo C albo jakiś tam inny, i sobie zaczniemy, zaczęlibyśmy tak radośnie alokować i zwalniać te, te obszary. No to zgodnie z najprostszym takim algorytmem po prostu bierzemy pierwszy wolny, zwalniamy go, to zostaje nam dziurka o takim rozmiarze, nie? I teraz możemy tak to sobie poszatkować, że już nie znajdziemy wystarczająco dobrego… Sumujemy wolną przestrzeń, to niby jest, ale zbyt poszatkowana, żeby nam zmieścić duży blok. Dokładnie.
Więc proces bądź wątek dostaje segment pamięci i sobie na nim robi alokacje, nie? Tam są już takie, no, no, no takie sprytniejsze lokatory, które potrafią sobie w obrębie tego segmentu podziałać. Jak się zdarzy tak, że w tym segmencie już nie ma miejsca, no to sorry, bierzemy następny, nie? I może się tak zdarzyć, że zwolnimy sobie cichcem pamięć tego pierwszego segmentu, więc on staje się wolny dla kolejnych takich właśnie wątków czy, czy procesów. Więc już tutaj mamy troszkę lżej, jeśli chodzi o fragmentację pamięci. Oczywiście Jawka, jak czy Jawka, no to nie musi być Jawka, to może być dowolny. Nawet w niezarządzanym języku możemy sobie zrobić własne zarządzanie pamięcią, na przykład jakiś wzorzec puli i możemy sobie zaalokować taki ciągły blok pamięci i samemu zadbać o to, żeby on nie był pofragmentowany, nie? I to się robi właśnie w takich wymagających zastosowaniach. Stąd się właśnie te wzorce też pojawiły. One są de facto kalką tych wzorców na z tego z tego niższego poziomu systemowego.
I no dobra, ale mamy te segmenty, musimy dbać o to, żeby zwalniać tą pamięć, bo jak nie zwalniamy, no to mamy wyciek pamięci. I wtedy na przykład system nam zwraca, że, że już nie ma dostępnych bloków dajmy na to, a powinny być, bo powinniśmy zwolnić te, których używaliśmy. No i to połowa biedy, jeżeli są to bloki przyspawane czy ogólnie w ogóle obszary przyspawane do procesu, bo jak ubijemy proces, to system odzyska tą pamięć. Ale jeżeli to są jakieś bloki współdzielone czy, czy coś w ten deseń, nie należą do jednego procesu i ciężko jest znaleźć ten moment, kiedy można zwolnić ten blok, a proces sam się nie kwapi, żeby go zwolnić. Aktualnie to są dość takie chyba rzadkie przypadki, bo jednak, jednak cała filozofia programowania poszła na tyle do przodu, że jesteśmy w stanie to wychwytywać, języki nam w tym pomagają. Jesteśmy w stanie zwalniać te zasoby dużo, w dużo bardziej przewidywalny sposób niż tam kiedyś, gdzie łatwo było przegapić coś i nikt nam o tym nie dał wskazówki. Dzisiaj nawet środowisko nam potrafi dać wskazówkę, że tu jest coś nie halo, bo zabrakło instrukcji zwalniających na przykład tą pamięć. No to łatwiej jest uniknąć takiej awarii, ale gdybyśmy tego nie unikali, w końcu wypaliłaby nam pamięć w komputerze po prostu. I dochodziło do takich sytuacji. Więc no na skutek tego te algorytmy stają się coraz lepsze i lepsze, ludzie tam wyszukują dziury i naprawiają.
Podsumowując, mamy dostęp do obszarów pamięci, z których korzysta nasz proces.
Operacje wejścia-wyjścia (I/O) i komunikacja międzyprocesowa
I teraz jak już tą pamięć, to chciałby na przykład coś na drukarkę wysłać, co nie? Albo jakieś inne I/O zrobić, niekoniecznie urządzenie peryferyjne. Urządzenie peryferyjne, ale też i I/O, czyli operacje wejścia-wyjścia, to są w ogólności operacje pisania i czytania z plików.
I tutaj jest takie szybkie przypomnienie: w systemach zaczynających się na „L” i kończących „nux” i ich pradziada Unix i wszystkich naokoło w tej samej architekturze – wszystko jest plikiem. Więc tam jest prosto. Więc tam nawet drukarka jest plikiem, skaner jest plikiem, wszystko jest wszystkim. Nawet taki pendrive USB też jest plikiem. No to akurat brzmi sensownie. Brzmi sensownie. No ale w Windowsie to on musi najpierw doznać instalacji drivera. Tam nie jest prostym plikiem, on jest tam czymś, czego jeszcze nie wolno było wyciągać do niedawna, bo groziło to katastrofą. Czy to jest jakaś aluzja do tego, że wszystkie problemy są gwoździem i masz tylko młotek? Nie, nie, absolutnie nie. No wszystkie te, wszystkie gwoździe w Uniksie są plikami. Są spoko i są spoko. Są plikiem. Okej, okej.
Dobrze. Ale to pokazuje, że można ujednolicić operację wejścia-wyjścia, bo właśnie po to to zostało wymyślone tak, a nie inaczej w Unixie, żeby wprowadzić jedno pojęcie pliku i jedno pojęcie operacji plikowej, nie? I ta operacja wejścia-wyjścia to jest albo pisanie do jakiegoś bufora. Zawsze to jest jakiś bufor w pamięci. Mamy bufor, który odpowiada za dany obszar takiego czy innego pliku, niezależnie od tego, czy to jest plik na dysku, czy to jest plik w pamięci. Na przykład może być RAM-dysk, nie? Amiga miała RAM-dyski. Amiga była inspirowana Uniksem w ogóle. Dlatego była taka fajna. I, i na przykład może to być właśnie taki bufor tej naszej drukarki czy skanera, nie? Czyli to, co, coś jakieś urządzenie peryferyjne albo jakiś plik, którego zawartość mamy na dysku, wrzuca nam dane do tego bufora, my wrzucamy jemu. I tak następuje wymiana danych pomiędzy tym, tym czymś. I to się nazywa I/O – wejście-wyjście. Brzmi prosto. Koniec tematu. Szybko poszło. Szybko poszło. Zdążymy, zdążymy. Już późno, nie?
Ale to nie wszystko, co, co można zrobić odnośnie komunikacji między… Aha, właśnie, bo to jeszcze można o komunikacji powiedzieć międzyprocesowej. W ogóle międzyprocesowej. Między, międzywątkowej w obrębie procesu ogarnięte, ale między procesami to już musielibyśmy zastosować jakieś sobie takie rozwiązania wykraczające troszkę poza strukturę samego procesu. No i tutaj na przykład socket dajmy na to. Socket jest plikiem. A w Windowsie to nie wiem, czym jestem. Jest po prostu, po prostu jakąś strukturą, do której się trzeba podpiąć jakoś tam i wtedy można sobie z niej czytać i do niej pisać. Windowsy mają bogatsze słownictwo. Nie wszystko dla nich plikiem. To jak czegoś umiesz nazwać, to nazywasz plikiem. To… no dobre, dobre, to mi się podoba. To one takie są, takie tego z wyższych sfer. Takie z wyższych sfer. Jak potrafisz wiesz, mieć synonimy na różne rzeczy, różnie nazywać, a nie, że wszystko jest plikiem. Wszystko jest plikiem i to: „Połącz mi drukarkę w potok ze skanerem”. Ale po co? No po co?
Nie, no okej. No i tak właśnie to się akurat da zrobić. No przykład jest trochę bez sensu, oczywiście naciągany, tendencyjny, wiadomo. Ale w Linuksie, czy ogólnie w Unixie, można sobie zrobić wyjście jednego pliku wejściem drugiego i to się nazywa potok. I to się wykorzystuje nagminnie, łącząc symbolem |
, czyli tej pały pionowej, kolejne komendy w Linuksie, w Unixie. Bo jak mówię Linux, to mam na myśli Unix. Linux to już jest taka w ogóle wisienka na torcie Unixów, nie? Ale zaczęło się od Unixów i od takiego podejścia plikowego. To niesamowite uproszczenie słownictwa pozwoliło zrealizować tak wspaniały mechanizm, który do dzisiaj jest obsługiwany na przykład w deweloperce i na serwerach wszelkiej maści. Konfiguracje są możliwe właśnie cała skryptowalność serwerów jest możliwa dzięki właśnie takim prostym trikom, nie? Bo skryptowanie Windowsa oczywiście jest możliwe, tylko to jest droga przez mękę z tego, co pamiętam. I żeby dobrze skryptować coś na Windowsie, najlepiej mieć tam Powershella albo Git Basha albo WSL, który jest po prostu okrojonym Linuksem i wtedy się da coś tam poskryptować. Nie polecam skryptować w tym ich nim, tym jak to się nazywa? W takim „command” jakiś napis tak. Bogate słownictwo mieli i i ten i Command to nazwali, żeby tam jedną komendę linijkę z tą komendą rzucić i dać enter i już nie. A rozumiem, że zaczęliśmy już hejt. No troszkę. Przepraszam, za wcześnie tak. Dobra, to się wstrzymam.
W Uniksie mamy konsolę, również bardzo pospolita nazwa. Pospolita, ale w konsoli zawsze masz i pokrętła jakieś, suwaki, inne takie, no i tam się dzieje po prostu. Masz komendy. Komend. No to w konsoli masz też komendy. Nie? No to terminal masz. Dobra.
Komunikacja międzyprocesowa może być oparta o jakieś tam pliki, pamięć na przykład współdzieloną pomiędzy procesami, o sockety. To są takie specjalne twory. No już nie będę mówił, że znowu pliki, ale po prostu urządzenia takie, które softwarowe, przez które można przepychać rzeczy. I to nie tylko pomiędzy procesami w obrębie tego samego systemu. Przez świat na świecie, nie? Czyli otwieramy sobie taki socket gdzieś tam do jakiegoś zdalnego systemu, nawiązujemy połączenie i już po kablu nam lecą tam nasze bity tam i z powrotem, nie? I to jest właśnie taka prosta komunikacja sieciowa, ale socket leży u podstawy tej komunikacji i wszystkie systemy współczesne muszą to obsługiwać, bo inaczej byśmy nie mieli internetów w ogóle.
I oczywiście tutaj wchodzą jeszcze tam protokoły sieciowe i inne takie dyrdymały, różne optymalizacje, które mamy. No na przykład Kafka, żeby zoptymalizować komunikację i wysyłanie właśnie przez sockety, to nie ładuje nawet danych do pamięci w żaden sposób, tylko bezpośrednio z bufora dysku rzucane jest wszystko na, na bufor socketu. Więc nie ma tego kroku ładowania do pamięci, no bo tutaj nie ma żadnej interpretacji tych danych. Wysyłamy binarnie dane z jednego bufora do drugiego. To jest taka… I tutaj z pomocą przyjdą sprzętowe po prostu kontrolery pamięci zapewne, które jakoś to ładnie przepchną. Te układy są też projektowane do takich zastosowań, żeby uniknąć niepotrzebnych transferów. Różne optymalizacje w stylu „write ahead”, „read before” to są też pewne, pewne triki, które powodują, że, że, że, że jednak ten dostęp z zasady taki trochę wolniejszy do I/O jakoś możemy przez bufory, przez pamięć przyspieszyć. No i też warto pamiętać, że wtedy ładujemy większej ilości danych do takiego bufora, no bo nie opłaca się tam szczypty wrzucać. Tylko bufory są też określonej wielkości, czasami potrafią być megabajtowe, jeżeli trzeba. No i muszą być po prostu takimi paczkami te dane wysyłane, żeby zaoszczędzić tego czasu.
No to co z komunikacji pykło szybko. Tutaj za bardzo wchodzić. Temat z tych nudniejszych, nie? Jeszcze nam zostanie, bo to są takie oczywiście tylko wybór tematów, bo w tych książkach to jest zdziebko więcej. Tak, no ciężko to streścić w dwóch, nawet czy trzech odcinkach dwa razy po tysiąc, kilka tysięcy stron. A i to też nie są wszystkie informacje. Oczywiście jeszcze są też inne książki, zwłaszcza że zahaczyliśmy też o troszkę architekturę komputerów, to też temat rzeka sam w sobie. Może dlatego tak po łebkach jedziemy, po takich najbardziej istotnych tutaj elementach. Najbardziej istotnych łebkach. Najbardziej istotnych łebkach.
Bezpieczeństwo systemu
No i takim jednym z istotniejszych jest bezpieczeństwo tego całego grajka. No i teraz to bezpieczeństwo to, to też jest temat rzeka, bo są nie takie książki o tym napisane. Ale no chodzi o to, żeby zapewnić jakąś izolację, co tam jest przetwarzane, od tego, co jest przetwarzane obok, żeby ktoś nam tu po prostu nie podejrzał takiego czegoś, nie? No bo jak już wiemy, że działa tutaj 5000 wątków, no to głupio by było, gdyby teraz 4000 wątków nam nagle zaczęło grzebać w naszym wątku. Google to potrafią chyba jakoś. Grzebią też potrafią. No w każdym ostatnio taki widziałem, czy jakiś filmik, tylko nie wiem, czy nie był naciągany, że ReSharper najnowszy śledzi po prostu trajektorię kursora, więc wykrywa roboty. No nie po tym, że jadą po prostej i klikają, bo co? Taki robot nie kliknie ci w kwadracik? Klik. To teraz jak będziesz widział ReSharpera, to musisz jechać jak robot, żeby zmienić… Będę próbował, to się może nie udać. Ale jeszcze ponoć sięga do tego, do historii przeglądarki. Nie wiem, prawda czy tylko prowokacja, żeby się ludzie zdenerwowali. Raczej prowokacja, bo historia przeglądarki chyba nie jest aż tak… Wydaje mi się, że właśnie tutaj security powinno jakieś być. Nie? Chyba że się zgodzimy. Ale tam była wzmianka, że się zgadzamy, to już jest jakby inny poziom zupełnie, bo mówimy o poziomie aplikacyjnym, a poziom bezpieczeństwa samego systemu o bezpieczeństwie systemowym, nie? Czyli taki na, na takim najniższym poziomie bezpieczeństwo w ogóle gwarantujące jakieś sensowne ramy wykonywania się procesów.
Zakładać, że właśnie procesy nie będą sobie nawzajem grzebać, czyli każdy proces jak już dostanie dostęp do swojej pamięci, nie może wyjść poza tą pamięć. I łatwo to sprawdzić w Javie, to ciężko, ale w C++ czy w C można sobie napisać program. Można sobie zrobić w nim pointer na NULL
, ustawić jakąś wartość, na przykład zero, całkiem. I o ile to tam jeszcze połowa biedy, bo to krzaki, i spróbować wyłuskać spod, rzutować na przykład na jakiś prosty obiekt. To się nie uda, dostaniemy błąd zwany segmentation fault. Pamięci trafimy na swój segment. To są takie wredne bugi, bo jak trafimy na nasze, to dostaniemy krzaki, ale swoje randomowe, no bo z Random Access Memory, ale własne. No i wtedy nam się aplikacja po prostu wykrzaczy. Natomiast jeżeli wyjdziemy poza naszą dozwoloną przestrzeń adresową, tą właśnie przestrzeń, którą mamy określoną w naszych strukturach w bloku kontrolnym procesu, no to nam system zrobi brzydko i powie nam „segmentation fault” i mamy takie tego typu błędy, które nam po prostu zatrzymują działanie procesu. Proces wtedy wypada w ogóle z kolejki. System się obraża, jest, jest urażony wtedy.
Systemy uprawnień
Kolejnym aspektem: tak, system uprawnień do plików, czy też do urządzeń. Nie wiem, czy mówiłem, ale w Unixie wszystko jest plikiem. Natomiast w Windowsach prędzej się przewinęło. Więc jeżeli mamy w Windowsie na przykład jego te pliki i foldery, nie katalogi. Mamy w Windowsie tylko foldery. Wszędzie mamy katalogi, a w Windowsie mamy foldery. Z jednych i drugich możemy sobie nadawać uprawnienia jakieś tam, nie? Nie wiem, czy one tam super działają, ale ogólnie działają w miarę. I ten, i jak nadamy uprawnienia, systemy uprawnień też różnie są realizowane. I na przykład systemy w Unixie jest taki popularny trójwarstwowy system, czyli są uprawnienia per użytkownik. W Windowsie jest kalka z tego: uprawnienia użytkownika. I do tego należą trzy wartości: R (read, czyli możemy przeczytać plik), W (write, czyli albo go przeczytać i zapisać, bo to są takie eskalujące), albo X (execute), zrobić, czyli go wykonać. Execute ma zastosowanie do oczywiście rzeczy wykonywalnych, czyli do kodu programów po prostu bądź skryptów na przykład. Plik może tekstowy zawierać skrypt, ale możemy chcieć go w jakimś interpreterze wykonać i wtedy on ma uprawnienie execute, czyli ma RX.
Nawet mogą, też, że Era trochę głupio się wtedy z nim współpracuje. Można do niego na przykład tylko wtedy pisać, jak ma samo W. Nie? No i takie, takie pola uprawnień są zdefiniowane dla użytkownika, czyli dla aktualnie pracującego, no z systemem, dla grupy, do której ten użytkownik przynależy, albo dla całego świata. Czyli możemy powiedzieć, że wszyscy użytkownicy, jakikolwiek by się nam nie napatoczył, mają takie uprawnienia, albo tylko ci w tej danej grupie, albo tylko tutaj. Przy czym całe to słowo opisu uprawnień w Unixie to jest po prostu już jednocześnie dla użytkownika, jego grupy i całego świata zestaw uprawnień kompletny. W Windowsach są tam odpowiednie checkboxy. No i w systemach podobnych też albo jest to zrobione tak unikowo albo checkbox. No i to właśnie decyduje, czy dany użytkownik może coś zrobić, czy nie. Może się fajnie mapuje na cyferki. Tak, na cyferki się mapuje, bo można to zakodować binarnie, więc tam na przykład 777 to nie polecam ustawiać na serwerach gdzieś tam gdziekolwiek.
Szyfrowanie i wirtualizacja
Tak, no i do tego pewnie nieodzownym aspektem całego bezpieczeństwa jest w ogóle szyfrowanie tam wszystkiego, czyli no głównie tutaj będziemy mieli zastosowanie tego szyfrowania w protokołach sieciowych. Ale jakbyśmy chcieli na przykład nie wiem, jeszcze wzmocnić bezpieczeństwo danego procesu, no to już możemy sobie jego dane szyfrować po prostu w jego obrębie, nie? Czyli dany kod programu może sobie tam używać szyfrowania do tego, żeby swoje dane ukryć przed innymi. No i przykładem tutaj są na przykład, przykładem na przykład są kryptowaluty, nie? Gdzie wszystko jest w ogóle zaszyfrowane zawsze dla wszystkich. No tak.
No i jeszcze nam zostały dwa wybrane aspekty takiego, tego właśnie no, aspekty systemów. Wsparcie dla wirtualizacji to jest dzisiaj ważna rzecz, bo kto odpalał Dockera na Windowsie, ten wie, czym to grozi, jeżeli nie jest odpowiednio skonfigurowane. Ale to nie musi być zwykły Docker, to może być na przykład jakaś poważniejsza maszyna wirtualna. Czyli możemy sobie zechcieć na przykład na jakimś systemie odpalić obraz z innego systemu. Albo dlatego, że pracujemy właśnie w ten sposób, albo po prostu lubimy eksperymentować i i się wygłupiać i sprawdzamy, jak wygląda AmigaOS odpalony na, na pececie. Albo no właśnie odpalamy Dockera, czyli mamy inną formę wirtualizacji, czy jakieś inne narzędzie podobne, bo potrzebujemy mieć odizolowany kawałek. Tak jakby system w systemie. Tak, tak, ale trochę lżejszy, niż tak trochę lżejszy. Albo, albo mamy w ogóle wielką chmurę i tam tniemy ją na, na te systemy, które my już sobie jako użytkownicy chmury kupujemy do nich dostęp albo alokujemy. I, i tam sobie wirtualizacja to chyba w ogóle jest taki temat też kolejna rzeka, zwłaszcza pojawiła się wraz z pojawieniem się Dockera i takich właśnie lżejszych kontenerów. No bo kiedyś wirtualne maszyny to raczej kojarzyły się z takimi dość ciężkimi procesami, które naprawdę emulowały. Emulatorami, tak, tak, tak, tak. Natomiast wraz z nadejściem takich lekkich kontenerów, gdzie mamy tylko tą warstwę software’ową, no to otwiera zupełnie nowe możliwości. Ale to jest, to jest pewnie też osobna dyskusja. Tutaj taka tylko mała uwaga, i to nie hejtowa, bo już, już naprawdę nie mam nic do tego Windowsa. On po prostu nie umie w Dockery. Musi mieć najlepiej to działa, jak ma właśnie ten podsystem Linuksa. Dlaczego? Dlatego że właśnie Dockery są, no skrojone pod Linuksy, mówiąc krótko. I Windows musi nam zaemulować to środowisko, żeby, żeby jakoś to mogło zadziałać. Natomiast jak… i to jest właśnie to, to porównanie, nie? Że musimy mieć osobne środowisko uruchomieniowe dla Dockera na Windowsie, a w Linuksie no też jakby osobne, ale inne jest zarządzanie zasobami z jego poziomu, bo wtedy dostajemy takiego sandboxa wykrojonego w tym właśnie Linuksie. Takiego, takiego Linuksa, gdzie jest zgodność już architektur systemowych w ogóle bardzo duża na tym poziomie.
Funkcje biblioteczne i API
No przebrnęliśmy. Czyli po prostu funkcje biblioteczne, które system operacyjny jako taki daje programistom, żebyśmy mogli otworzyć plik, zamknąć plik, pociągnąć z niego dane, zapisać do niego dane, otworzyć socketa, złapać z niego timeout, wszystkie te rzeczy, które albo utworzyć proces, utworzyć wątek. Nie? Zaalokować pamięć. Wszystko to, o czym do tej pory powiedzieliśmy, w jakiś tam sposób znajduje odzwierciedlenie w tych właśnie funkcjach bibliotecznych. I to są, to jest takie podstawowe API do systemu, tak, żebyśmy sami się nie musieli przejmować, jak obsłużyć ten czy inny dysk, czy czy wspomnianego wcześniej Sound Blastera. Właśnie tak, rolą systemu jest jednak to, żeby nam poprzez takie proste API i spójne dla wszystkich można powiedzieć systemów czy wersji, żeby to tej rodziny, na przykład z tej rodziny, żeby, żeby to działało jednolicie. No i no to tak chyba na co dzień może nie doceniamy tego aspektu. Doceniamy, jak się czyta takie książki. Taka książka z lat 90, nie? Czytałem 90, chyba 5 i 8. To też taka Biblia. I tam jest API na przykład linuksowe rozpisane. WinAPI, tak, tak, tak, tak. A gdzieś tam mam w ebookach takie chyba 1500 stron, podstawy programowania w Linuksie. Także trochę tego jest. Podstawy, podstawy, wstęp, wstęp do programowania. Już dzisiaj nie zdążymy zreferować. Raczej nie, raczej nie. To jutro.
Ewolucja systemów operacyjnych
Także chyba już przeszliśmy przez większość takich najważniejszych tematów. Ten podział systemów to też już tak gdzieś tu się chyba przewijał, tak. No już zdążyliśmy siedem razy chyba. No i tak jak też podkreślaliśmy, jest kilka rodzin systemów. Rodzina unikowa, która gdzieś też jest najlepsza. Najlepsze systemy mobilne właśnie Androidem z logiem jabłka, i to też jest jakby już nowa rodzina systemów, która pojawiła się na urządzenia mobilne, czy chociażby Android TV, czy ogólnie jakieś mobilne na jeszcze inne urządzenia, czyli to jakieś tam branchowanie i odgałęzienie się tych systemów wciąż następuje i tak naprawdę no, widać, że to wciąż krajobraz się zmienia. To nie jest tak, że że to jest… Przybywa go. No przybywa. Pewnie ci już stali bywalcy się utwardzają, umacniają w tych pozycjach. Ciężko chyba teraz wymyśleć nowy system i wejść z nim.
Tak, ciekawy, ciekawy wątek poruszasz. Mamy kolejną godzinę, nie? To, to w największym skrócie telegraficznym. Można by sobie wyobrazić wprowadzenie nowej platformy całkiem, bo jest bardzo przyjemnie sobie siąść, wymyślać, brać od poprzedników sprawdzone rozwiązania, zaprojektować całe wszystko, wziąć cały sztab ludzi. Niech to kodują przez 3 lata. Tylko jak wypuścimy takie nowe cacko totalnie w nowej architekturze, niekompatybilne z czymkolwiek, co istnieje, to skąd weźmiemy na to programy i użytkowników? Nie? To, to jest właśnie ten problem. Tak, dlatego właśnie ta, ta ewolucja systemów idzie już w oparciu o to, co się utrwaliło na rynku. Czyli po prostu kolejne dystrybucje Linuksów, Unix, Windowsów. Z Linuksów wyczek… To jest jedna rzecz, ale druga rzecz to chyba są też przyzwyczajenia użytkowników. Ciężko zmienić przyzwyczajenia użytkowników, jeśli od lat siedzi się na jednym systemie, co widać chociażby po Windowsie, który… Czy może bardziej po Linuksie, który jeszcze niedawno każdy rok był ogłaszany rokiem Linuksa. Natomiast jego udział w rynku chyba stabilnie się utrzymuje tam na kilku procentach. Nie? To zależy, jaki rynek sprawdzimy.
Sprawdzimy rynek na przykład serwerów linuksowych, oczywiście to, to tam jest, albo rynek twoich prywatnych komputerów, tam będzie 100%. Tam to będzie 200%. Także nie, po prostu zależy do jakich zastosowań i zależy, jaki… nie lubię tego słowa, ale jaki target weźmiemy konsumentów albo profesjonalistów. Bo no, bo właśnie no, dla nas, jeżeli na przykład projekt informatyczny zakłada wdrożenie cacka na infrastrukturze Windowsowej, no to nie zobaczymy tam zanadto Linuksów, nie? Chociaż jak się wejdzie na platformę Azure, to tam się roi od maszyn linuksowych z jakiegoś powodu. Nie? Czasem po prostu właśnie muszą być te Windowsy i koniec kropka. Nie? Czasem musi być ani Linux, ani Windows, tylko jakieś coś embedded. O tym jeszcze nie mówiliśmy, nie? To, to może nam się kroi kolejny odcinek jakoś z tego. Jakoś trochę, chociaż, bo jeszcze tego hejtu nie, nie zdążymy dzisiaj. Ale jeżeli znowuż odwrócimy to wszystko i i weźmiemy jakieś poważne środowiska serwerowe, no to tutaj dostajemy praktycznie same Linuksy, nie? Więc zależy, kogo zapytamy, nie? Jak, jak mamy ciocię, wujka i i dziadków, którzy siedzą od lat 90 na Windowsie 95,
To będzie Windows.
To będzie Windows. Nie?
I to pewnie wciąż 95.
Będzie 95. Nie wiem, czy to jeszcze zipie, kurka. Ale jak weźmiemy nawet użytkowników takich, którzy już zdążyli Windowsa znienawidzić, albo przynajmniej są zainteresowani czymś innym, no to oni będą szukać szczęścia w Linuksie, nie? Dojdziemy też do takich, którzy już na Linuksie potracili wszelką nadzieję i z powrotem przeszli gdzieś tam, nie? Jeszcze mamy takich nostalgicznych, jak ja też, że jakbym dorwał Amigę, to po prostu bym se po niej polikał.
No tak. Czyli dla każdego coś się znajdzie.
No i wszechobecne Androidy, jakieś iOS-y, inne takie. Właśnie ten, ten Windows mobilny nie za specjalnie się chyba przyjął, nie?
Nie.
Bo bo coś tutaj nie pykło. Ale być może to już była wina przepełnienia rynku Androidem i iOS-em.
Możliwe, że to już było za późno.
Jeszcze był jakiś ChromeOS, który też próbował tam coś uszczknąć.
Tak, tak. No to podobnie, jak w przypadku mobilnego systemu Microsoftowego, który chciał Microsoft wprowadzić w przypadku Nokii, to też zupełnie nie chwyciło, mimo że przez pewien czas gdzieś tam te…
Ale to było po Symbianie?
Tak, tak, tak, tak.
No Symbian już też jest muzealnym, że tak powiem, tworem. Jeszcze było Blue… jak to się nazywało… Te jagódki takie?
BlackBerry.
BlackBerry, tak.
BlackBerry jako producent telefonów oczywiście już nie produkuje…
Ale nie wiem, czy on tam Symbiana nie miał, ten BlackBerry?
To chyba ich był własny system jakiś tam. Ale BlackBerry mocno działa obecnie na rynku bezpieczeństwa, bo generalnie BlackBerry było znane właśnie z różnych algorytmów bezpieczeństwa i tego typu rzeczy. I BlackBerry teraz akurat się w tym specjalizuje, więc znaleźli tak, znaleźli swoją niszę.
Nie poszło im z systemem, nie przepaliło się. Nie?
No i na samochody też produkują. Bardzo mocno są dwa, dwa takie targety obecne. Dobra, myślę, że chyba już wyczerpaliśmy limit na dzisiaj, a także listy tematów. Przeskoczyliśmy tak troszkę chyba chaotycznie przez przez część rzeczy.
Ale materiał jest obszerny.
Materiał jest obszerny i zachęca do dygresji.
Zachęca. Nie było wstawek kulturalnych zbyt wiele.
Wiedźmin się gdzieś tam przewinął, ale delikatnie.
Delikatnie, symbolicznie.
Nadrobimy następnym razem.
Nie zhejtowaliśmy żadnego serialu.
No nie, w sumie to nie wiem, nic ostatnio nie oglądałem wartego hejtu, więc, więc ciężko.
Ale Flasha można polecić dla odmiany jako taką rozwałkę.
Można.
A i szykujcie się na „Diunę” wszyscy, bo ja już się szykuję. Bo będzie. Niedługo, nie? Za miesiąc to trzeba zdążyć przeczytać jeszcze raz. Przeczytałeś już swoją „Diunę”?
A „Diuna” nie była przełożona?
Jak przełożona? Przepraszam najmocniej.
„Diuna” jest przełożona przecież
Na co?
15 marca 2024. Także…
…zdążę przeczytać.
Także jeszcze nie trzeba się szykować, jak widać. Jeszcze jedynkę nadrobić, albo może, albo pograć w grę „Dune”, który chyba wyszedł z early accesu, zdaje się.
Tak, wyszła. Tam dodali nowy, nowy House. Zapomniałem nazwy. Jakiś taki…
Ja nie grałem, tylko widziałem…
Ale muszę chyba doczytać z powrotem książkę, bo coś mi się ten, ten ród nie kojarzy jakoś. Ale pewnie był, skoro go dodali.
Nie czytałem, więc, więc się nie wypowiem.
Spoko.
Dobra, to co? Dzięki, Michał, za dzisiaj.
Bywaj.
Bywaj. Miało być „bywaj”. No to bywam.
To bywaj.