List

Aplikacje przetwarzające wiele wątków

Rozważmy sytuację, gdy aplikacja serwera jest dostępna do publicznego użytku i potrzebuje np. 30 sekund ciągłych obliczeń do obsługi jednego zapytania od klienta. Pojawia się problem, gdy w tym czasie inne aplikacje klienckie spróbują połączyć się do naszego serwera.Najprostsze dwa rozwiązania to:

  • wiele procesów – po otrzymaniu połączenia stworzenie procesu potomonego (fork) i przekazanie deskryptora tego procesu połączenia do nowego procesu, podczas gdy proces macierzysty powróci do oczekiwania na połączenie,
  • wiele wątków – po otrzymaniu połączenia stworzenie procesu potomonego (fork) i przekazanie deskryptora tego procesu połączenia do nowego procesu, podczas gdy proces macierzysty powróci do oczekiwania na połączenie

W tym artykule skupiam się na rozwiązaniu problemu poprzez stworzneie aplikacji wielowątkowej. Wątki wykorzystują zdefiniowaną przez nas funkcję/procedurę, która będzie uruchomiona równolegle niezależnie od całości programu, tj. pozwoli na przetworzenie dwóch lub więcej instancji tej funkcji przez nasz program w taki sposób jak by działały równolegle.

Wprowadzenie i definicje

Biblioteka pthreads pozwala na uruchamianie rónolegle wielu funkcji zwanch wątkami.

Wątki te współdzielą:

  • PID, PPID,  id grupy procesów, id sesji,
  • otwarty terminal,
  • identyfikator właściciela i grupy,
  • otwarte pliki, bieżący katalog,
  • rlimity, priorytet nice,
  • otwarte pliki (z blokadami odczytu – by konkurente wątki nie konkurowały o zasób), maskę tworzenia nowych plików,
  • liczniki czasu – znane z polecenia time.

Wątki mają jednak różne:

  • identyfikatory
  • funkcje błędów,
  • obsługę sygnałów,
  • algorytm szeregowania grupy wątków,
  • linux capabilities (obok procesów uprzywilejowanych i nieuprzywilejowanych, jądro linux od wersj 2.2 zaimplementowało odrębny zestaw zdolności procesów, które mogą być włączone lub wyłączone),
  • cpu affinity (zbiór procesorów, na których zadanie może być przetwarzane).

Typy zmiennych:

  • pthreads_t – identyfikator wątku
  • pthread_attr_t – atrybuty wątków

Funkcje podstawowe:

  • int pthread_create(pthread_t *id, const pthread_attr_t *attr, void* (*fun)(void*), void* arg) – uruchomienie wątku, nadanie mu identfikatora do id (przypisujemy do adresu wskaźnika), przekazanie atrybutów pthread_attr_t(można podać NULL – zostaną ustawione domyślne atrybuty), wskazanie adresu funkcji, która ma zostać wywołana fun, przekazanie przez wskaźnik argumentu arg (może to być wskaźnik na dowolną zmienną lub strukturę),
  • int pthread_join(pthread_t id, void **retval)  – oczekiwanie na zakończenie działania wątku o identyfikatorze id oraz pobranie wartości zwróconej przez ten wątek retval (może to być wskaźnik na strukturę)

Funkcje dodatkowe:

  • int pthread_detach(pthread_t id) – zmiana wątku na typ detached (tj. taki, który zwalania pamięć po zakończeniu bez konieczności  wywołania pthread_join)
  • pthread_t pthread_self() – zwraca wartość id wątku, w którym jest wywołana
  • int pthread_equal(pthread_t id1, pthread_t id2) – porównuje identyfikatory dwóch wątków (w różnych systemach pthread_t możę mieć inn
  • void pthread_exit(void *retval) – zakończenie wątku, który wywołał tą funkcję

Argumenty:

  • id – identyfikator wątku (jeśli stworzymy tablicę identyfikatorów – wówczas podajemy np. &tablica[pozycja])
  • pthread_attr_t – atrybuty wątku (jeśli podamy NULL brane są domyślne)
  • fun – wskaźnik na funkcję, która ma zostać wykonana, powinna przyjmować argumenty typu *void i zwracać *void
  • arg – wskaźnik na argument przekazany do funkcji (w przypadku zadeklarowanej tablicy jest to po prostu jej nazwa)
  • retval – wskaźnik na wartość wynikową wątku, jeśli NULL wynik będzie ignorowany

Rodzaje wątków:

  • joinable  – wątek, który zakończył swoje działanie, do czasu wywoł
  • detached

Przykład

Przykład 1

Poniżej znajduje się przykład aplikacji, która będzie stworzy dwa wątki.

Przykład 2

Aplikacja wielowątkowa z socketami:

Zwróćmy uwagę, że aplikacja w nieskońćzonej pętli oczekuje na połączenia, a w przypadku, gdy do połączenia dochodzi tworzy nowy wątek, który otrzymuje socket jako argument i może przeprowadzić bezpośrednią komunikację z klientem.

Zadania

  1. Zmień aplikację z przykładu 1 tak by powstało 5 równoległych wątków, z których każdy wypisze wiadomosc, odczeka 10 sekund i ponownie wypisze wiadomość.
  2. Napisz aplikację serwera, który po połączeniu klienta będzie wypisywał zawartość jakiegoś pliku, przesyłając 10bajtów na sekundę. Serwer po uruchomieniu będzie nasłuchiwał na porcie 10000. Napisz aplikację klienta, która będzie się łączyła z serwerem opisanym powyżej, a po połączeniu będzie odczytywała plik przesyłany przez serwer i zapisywała go w lokalnym katalogu pod losową nazwą.

 

Ciekawostki:

  • zmienna PTHREAD_THREADS_MAX z limits.h określa maksymalną liczbę wątków, które można uruchomić,
  • Przykładowe operacje na atrybutach wątków:
    • int pthread_attr_init(pthread_attr_t *attr) – wypelnienie attr domyślnymi wartościami,
    • int pthread_attr_destroy(pthread_attr_t *attr) – usunięcie struktury opisującej atrybuty wątków (bez wpływu na działanie wątków, które przy jej pomocy zostały utworzone),
    • int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) – ustawienie rodzaju wątku (PTHREAD_CREATE_JOINABLE, PTHREAD_CREATE_DETACHED),
    • int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) – odczytanie rodzaju wątku,
    • int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) – ustawienei rozmiaru stos,
    • int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) – pobranie informacji o rozmiarze stosu,
    • int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched) – odczytanie informacji o algorytmie szeregowania,
    • int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) – ustawienie algorytmu szeregowania np. SCHED_FIFO, SCHED_RR.

  Posts

May 20th, 2017

Different kernel types

https://en.wikipedia.org/wiki/Kernel_%28operating_system%29#Kernel-wide_design_approaches https://en.wikipedia.org/wiki/Unikernel https://en.wikipedia.org/wiki/Exokernel https://en.wikipedia.org/wiki/Nemesis_%28operating_system%29 http://windowsitpro.com/windows-server/top-ten-what-you-need-know-about-microsoft-nano-server

April 21st, 2017

Microsoft Roadmap for AzureStack

Microsoft’s Hyper-V looked really promising and it happened to be really good general purpose virtualization. Not it’s time for on-premise/hybrid […]

April 21st, 2017

Books reading :)

Mind development requires regular reading 🙂 Here are some advices: http://www.gq.com/story/how-to-read-a-whole-damn-book-every-week?mbid=synd_digg For me reading in the morning would be the best […]

October 25th, 2016

Linux – powłoka bash – skrypty 2

Wykorzystanie cydzysłowie: ‘   oraz   ‘ – apostfory służą do łączenia zawartych w nim znaków jako jeden ciąg znaków. Jest to […]

June 9th, 2016

Session data in Redis (with PHP exapmle)

Session data in Redis What is session Session is What is cookie Cookie is something you eat 🙂   How […]

June 7th, 2016

DSIK, DASL – Brama domyślna

Linux jako ruter Naszym celem będzie skonfigurowanie systemu linux jako urządzenia przesyłającego pakiety. W tym celu będziemy potrzebowali: uruchomić infrastrukturę (w […]

May 25th, 2016

How to change a hostname

Just a few easy steps: Manually update: /etc/hostname /etc/hosts it may be important to update some other files – see https://wiki.debian.org/HowTo/ChangeHostname […]

May 10th, 2016

Gartner Hype Cycle through last 10 years :)

I recently read about self driven cars and jumped into Gartner Hype Cycle term.   Brief introduction to the subject: […]

May 6th, 2016

Bug bounty program

I’ve recently heard about the Bug bounty idea – a program for rewarding IT geeks (with just recognition or even […]

April 26th, 2016

Is IBM’s Power8 powerful enough? :)

Recently I heard about Power8 platform designed “for Magento”.  Obviuosly, somebody from marketing had a great idea to ad the general platform […]

April 26th, 2016

DSIK – Zajęcia 8 – Raw Sockets

Surowe gniazda Na wcześniejszych zajęciach poznaliśmy metodę wykorzystywania funkcji systemowych do tworzenia nagłówków IP oraz warstwy TCP i UDP. Dzięki wykorzystanym funkcjom system automatycznie […]

April 25th, 2016

2016.04.25 – Etap 4

MedicaLibaro Paweł Banach, Rafał Pingot, Piotr Beczyński. Moodies Rafał Maszkowski, Mateusz Kulesza, Dawid Krawczyk.

April 24th, 2016

DSIK – Zajęcia 8 – Projekt – podział na grupy, wybór tematów

Wybrane grupy projektowe i przypisane tematy. Lista: Rutka, Sosnowski – serwer HTTP Nojnam, Ciuk – klient IRC Soprych, Macutkiewicz – […]

April 18th, 2016

DSIK – Zajęcia 0 – Plan zajęć.

Plan przedmiotu Zajęcia 1-8: Część zgodna z dotychczasowym harmonogramem. Wprowadzenie teoretyczne do warstwy 2 i 3. Diagnostyka sieci – polecenia. Gniazda […]

April 18th, 2016

DSIK – Zajęcia 7 – Projekt określenie wymagań

Zasady zaliczenia: projekt tworzy grupa 2 osobowa projekt obejmuje: napisanie programu: zaimplementowanie znanego protokołu (może być REST API, może być protokół […]

April 11th, 2016

DSIK – Zajęcia 5 – UDP, aplikacje socket bezpołączeniowe

Komunikacja bezpołączeniowa UDP (z ang. User Datagram Protocol – protokół  datagramów użytkownika) to bardzo lekki protokół umożliwiający przesyłanie komunikatów między klientem […]

April 7th, 2016

DSIK – Zajęcia 2 – Stos TCP/IP – Warstwa 3, polecenia diagnostyczne.

April 7th, 2016

DSIK – Zajęcia 6 – Sockety Unix.

Opis problemu Komunikacja sieciowa jest bardzo elastycznym elementem komunikacji, jednakże niesie za sobą narzut obliczeniowy w postaci obsługi stosu TCP/IP po […]

April 4th, 2016

DSIK – Zajęcia 4 – Nieblokujące programowanie gniazd.

Opis problemu Załóżmy, że napisaliśmy program działający jako serwer pewengo protokołu (np. xmpp), który oczekuje na komunikaty od użytkownika, ale […]

April 4th, 2016

DSIK – Zajęcia 4 – Aplikacje wielowątkowe

Aplikacje przetwarzające wiele wątków Rozważmy sytuację, gdy aplikacja serwera jest dostępna do publicznego użytku i potrzebuje np. 30 sekund ciągłych obliczeń […]

March 14th, 2016

DSIK – Zajęcia 3 – Sieci komputerowe – programowanie gniazd, wstęp (TCP klient i serwer).

Programowanie gniazd. Funkcje: ssize_t send(int sockfd, const void *buf, size_t len, int flags); – możliwość wykorzystnia tylko gdy socket jest […]

March 14th, 2016

DSIK – Zajęcia 1 – Stos TCP/IP – Warstwa 2, polecenia diagnostyczne.

Stos TCP/IP TCP/IP to rodzina protokołów stanowiących podstawę do komunikacji między komputerami w sieciach komputerowych. Do rodziny tej zaliczmy protokoły zapewniające adresowanie i […]