Ogolne operacje na watkach

  1. utworzenie nowego watku
  2. pthread_create

    Deklaracja

    #include <pthread.h>

    int pthread_create(pthread_t * thread, pthread_attr_t *

    attr, void * (*start_routine)(void *), void * arg);

    Opis

    Funkcja pthread_create tworzy nowy watek, ktory wykonuje sie wspolbieznie z watkiem wolajacym. Nowy watek zaczyna wykonywac podana funkcje start_routine podajac jej arg jako pierwaszy argument. Nowy watek konczy sie explicite przez wywolanie procedury pthread_exit lub przez powrot z start_routine.

    Argument attr okresla atrybuty nowego watku, do ktorych ustalenia sluzy funkcja pthread_attr_init. Jesli jako attr przekazemy NULL, zostana okreslone domyslne atrybuty watku: mozliwosc dolaczenia, domyslny sposób kolejkowania (nie czasu rzeczywistego).

    Po bezblednym wykonaniu pthread_create umieszcza identyfikator nowoutworzonego watku w miejscu wskazywanym przez argument thread i zwraca 0.

    W razie bledu zwracane jest EAGAIN w przypadku, gdy brakuje zasobow systemowych zeby stworzyc proces dla nowego watku lub gdy wiecej niz PTHREAD_THREADS_MAX watkow juz dziala w systemie.

  3. ustawianie atrybutow przy tworzeniu watkow
  4. pthread_attr_init, pthread_attr_destroy,

    pthread_attr_setdetachstate, pthread_attr_getdetachstate,

    pthread_attr_setschedparam, pthread_attr_getschedparam,

    pthread_attr_setschedpolicy, pthread_attr_getschedpolicy,

    pthread_attr_setinheritsched,

    pthread_attr_getinheritsched, pthread_attr_setscope,

    pthread_attr_getscope

    Deklaracja

    #include <pthread.h>

    int pthread_attr_init(pthread_attr_t *attr);

    int pthread_attr_destroy(pthread_attr_t *attr);

    int pthread_attr_setdetachstate(pthread_attr_t *attr, int

    detachstate);

    int pthread_attr_getdetachstate(const pthread_attr_t

    *attr, int *detachstate);

    int pthread_attr_setschedpolicy(pthread_attr_t *attr, int

    policy);

    int pthread_attr_getschedpolicy(const pthread_attr_t

    *attr, int *policy);

    int pthread_attr_setschedparam(pthread_attr_t *attr, const

    struct sched_param *param);

    int pthread_attr_getschedparam(const pthread_attr_t *attr,

    struct sched_param *param);

    int pthread_attr_setinheritsched(pthread_attr_t *attr, int

    inherit);

    int pthread_attr_getinheritsched(const pthread_attr_t

    *attr, int *inherit);

    int pthread_attr_setscope(pthread_attr_t *attr, int

    scope);

    int pthread_attr_getscope(const pthread_attr_t *attr, int

    *scope);

    Opis

    Ustawianie atrybutow watkow odbywa sie przez wypelnianie struktury attr typu phread_attr_t (obiektu atrybutow) i nastepnie przekazanie jej jako drugi argument funkcji pthread_create. Przekazanie wartosci NULL odpowiada przypisaniu wszystkim atrybutom ich domyslnych wartosci (domyslne wartosci dla poszczegolnych atrybutow wypisane sa ponizej).

    pthread_attr_init inicjalizuje obiekt attr i wypelnia wszystkie atrybuty ich domyslnymi wartosciami.

    Kazdy atrybut attrname (ponizej lista dostepnych atrybutow) moze być idnywidualnie ustawiony za pomoca funkcji pthread_attr_setattrname i odczytany za pomoca pthread_attr_getattrname.

    pthread_attr_destroy niszczy obiekt typu pthread_attr_t (w tej implementacji nie robi faktycznie nic).

    Obiekt atrybutow jest analizowany jedynie podczas tworzenia nowego watku. Ten sam obiekt atrybutow moze byc uzyty do stworzenia wielu watkow. Modyfikacja obiektu atrybutow po wywolaniu pthread_create nie zmienia atrybutow watku wczesniej utworzonego.

    Dostepne sa nastepujace atrybuty:

    detachstate

    Okresla czy watek ma byc utworzony w stanie umozliwiajacym dolaczenie (wartosc PTHREAD_CREATE_JOINABLE), czy odlaczonym (PTHREAD_CREATE_DETACHED).

    Wartoscia domyslna jest PTHREAD_CREATE_JOINABLE.

    W stanie umozliwiajacym dolaczenie inny watek moze oczekiwac na zakonczenie i odczytac wartosc zakonczenia danego watku za pomoca pthread_join, ale czesc zasobow przydzielonych do danego watku zostanie w pamieci nawet po jego zakonczeniu, do momentu az inny watek nie wywola na nim pthread_join.

    W stanie odlaczonym zasoby rezerwowane dla watku sa zwalniane zaraz po jego zakonczeniu, jednak pthread_join nie moze byc uzyty do synchronizacji.

    Watek stworzony w stanie umozliwiajacym dolaczenie moze byc w kazdym momencie odlaczony przez wywolanie pthread_detach.

    schedpolicy

    Umozliwia wybor sposobu przelaczania dla watku. Mozna wybrac:

    SCHED_OTHER (normalne, przelaczanie nie w czasie rzeczywistym),

    SCHED_RR (w czasie rzeczywistym, round-robin),

    SCHED_FIFO (w czasie rzeczywistym, FIFO).

    Wartoscia domyslna jest SCHED_OTHER.

    Uwaga! Sposoby SCHED_RR i SCHED_FIFO sa dostepne jedynie dla procesow z uprawnieniami superuzytkownika.

    Sposob kolejkowania moze byc zmieniony w czasie dzialania watku przez wywolanie pthread_setschedparam.

    schedparam

    Zawiera parametry do przelaczania (priorytet) watku.

    Wartoscia domyslna jest priorytet 0.

    Wartosc priorytetu nie ma znaczenia jesli sposob kolejkowania jest ustawiony na SCHED_OTHER. Ustawienie ma sens jedynie przy sposobach czasu rzeczywistego SCHED_RR lub SCHED_FIFO.a

    Priorytet moze byc zmieniony w czasie dzialania watku przez wywolanie pthread_setschedparam.

    inheritsched

    Okresla kiedy sposob przelaczania i parametry z nim zwiazane dla nowo tworzonego watku sa explicite ustalone przez wartosci schedpolicy i schedparam (PTHREAD_EXPLICIT_SCHED) lub sa dziedziczone z watku-ojca (PTHREAD_INHERIT_SCHED).

    Domyslna wartoscia jest PTHREAD_EXPLICIT_SCHED.

    Zwracane wartosci:

    Wszystkie funkcje zwracaja 0 w razie sukcesu i kod bledu przy niepowodzeniu.Po poprawnym zakonczeniu funkcje pthread_attr_getattrname wkladaja aktualne wartosci atrybutow w miejsce okreslone przez drugi argument funkcji.

    W razie bledu funkcja pthread_attr_setdetachstate zwraca EINVAL, co oznacza, ze podany parametr detachstate nie jest ani PTHREAD_CREATE_JOINABLE ani PTHREAD_CREATE_DETACHED.

    Funkcja pthread_attr_setschedparam zwraca EINVAL, gdy podany priorytet jest poza zakresem dla sposobu przelaczania okreslonego w innym atrybucie (1 .. 99 dla SCHED_RR i SCHED_FIFO i 0 dla SCHED_OTHER).

    Funkcja pthread_attr_setschedpolicy zwraca EINVAL jesli sposob przelaczania nie jest poprawny (SCHED_RR, SCHED_FIFO lub SCHED_OTHER) lub ENOTSUP jeśli sposob przelaczania jest ustawiony na SCHED_RR lub SCHED_FIFO i proces nie ma uprawnien superuzytkownika.

    Funkcja pthread_attr_setinheritsched zwraca EINVAL, gdy podany argument nie jest PTHREAD_INHERIT_SCHED ani PTHREAD_EXPLICIT_SCHED.

  5. kontrola sposobu przelaczania watkow
  6. pthread_setschedparam, pthread_getschedparam

    Deklaracja

    #include <pthread.h>

    int pthread_setschedparam(pthread_t target_thread, int policy,

    const struct sched_param *param);

    int pthread_getschedparam(pthread_t target_thread, int *policy,

    struct sched_param *param);

    Opis

    Funkcja pthread_setschedparam ustawia parametry przelaczania dla watku target_thread wg podanych wartosci policy i param. policy moze miec wartosc:

    SCHED_OTHER (normalne, przelaczanie nie w czasie rzeczywistym)

    SCHED_RR (w czasie rzeczywistym, round-robin)

    SCHED_FIFO (w czasie rzeczywistym, FIFO).

    Param okresla priorytet przelaczania przy sposobie czasu rzeczywistego.

    Uwaga! Sposoby SCHED_RR i SCHED_FIFO sa dostepne jedynie dla procesow z uprawnieniami superuzytkownika.

    Funkcja pthread_getschedparam pozwala sprawdzic sposob przelaczania i priorytet dla watku podanego jako target_thread. Wyniki umieszcza w miejscach wskazanych przez policy i param.

    Obie funkcje zwracaja 0 jesli zakonczyly dzialanie bez bledu lub nastepujace wartosci w razie bledow:

    EINVAL - wartosc policy nie jest SCHED_OTHER, ani SCHED_RR, ani SCHED_FIFO

    EINVAL - priorytet podany jako parametr nie pasuje do sposobu przelaczania

    EPARM - wywolujacy funkcje proces nie ma uprawnien superuzytkowanika

    ESRCH - watek target_thread nie istnieje lub zakonczyl dzialanie

    EFAULT - wskaznik param lub policy wskazuje poza obszar pamieci dostepny dla procesu.

  7. uzyskanie wlasnego identyfikatora
  8. pthread_self

    Deklaracja

    #include <pthread.h>

    pthread_t pthread_self(void);

    Opis

    pthread_self zwraca identyfikator watku, ktory wywolal funkcje.

  9. porownanie dwoch identyfikatorow watkow
  10. pthread_equal

    Deklaracja

    #include <pthread.h>

    int pthread_equal(pthread_t thread1, pthread_t thread2);

    Opis

    Funkcja pthread_equal okresla, czy oba identyfikatory odnosza sie do tego samego watku.

    Zwraca niezerowa warosc jesli thread1 i thread2 odnosza sie do tego samego watku. W przeciwnym przypadku 0 jest zwracane.

  11. zakonczenie dzialania watku
  12. pthread_exit

    Deklaracja

    #include <pthread.h>

    void pthread_exit(void *retval);

    Opis

    Funkcja pthread_exit konczy dzialanie wolajacego watku. Wywolywane sa po kolei (LIFO) wszystkie funkcje czyszczace okreslone przez pthread_cleanup_push. Funkcje konczace dla wszystkich kluczy odnoszacych się do konkretnego watku i majacych wartosc inna niz NULL (patrz pthread_key_create) sa wykonywane. Dopiero po tym wszystkim dzialanie watku jest wstrzymywane. Argument retval okresla kod zakonczenia watku, ktory może byc odczytany przez inny watek za pomoca funkcji pthread_join.

  13. oczekiwanie na zakonczenie innego watku
  14. pthread_join

    Deklaracja

    #include <pthread.h>

    int pthread_join(pthread_t th, void **thread_return);

    Opis

    Funkcja pthread_join zawiesza dzialanie wolajacego watku az do momentu, gdywatek identyfikowany przez th nie zakonczy dzialania. Jesli argument thread_return jest rozny od NULL to kod zakonczenia watku th zostanie wstawiony w miejsce wstazywane przez thread_return. Kodem zakonczenia może byc wartosc okreslona pzy wolaniu funkcji pthread_exit lub PTHREAD_CANCELLED jesli watek byl usuniety.

    Watek, do ktorego dolaczamy musi byc w stanie umozliwiajacym dolaczanie (nie moze byc odlaczony przez wywolanie pthread_detach lub okreslenie atrybutu PTHREAD_CREATE_DETACHED przy jego tworzeniu przez pthread_create).

    W momencie, gdy watek w stanie umozliwiajacym dolaczenie konczy dzialanie jego zasoby (deskryptor watku i stos) nie sa zwalniane dopoki inny watek nie wykona na nim pthread_join. Dlatego pthread_join powinien byc wykonany dla kazdego nie odlaczonego watku.

    Co najwyzej jeden watek moze czekac na zakonczenie danego watku. Wywolanie pthread_join w momencie, gdy jakis inny watek juz oczekuje na jego zakonczenie spowoduje powrot z funkcji pthread_join z bledem.

    Oczekiwanie przez wywolanie funkcji pthread_join jest tzw. cancellation-point, co oznacza, ze jesli watek zostanie odwolany (canceled) w czasie oczekiwania, to dzialanie watku zostanie zakonczone natychmiast bez czekania na synchronizacje z watkiem th.

    W przypadku sukcesu funkcja pthread_join zwraca 0 i kod zakonczenia watku th jest umieszczany w miejscu wskazywanym przez thread_return. W przypadku bledu zwracana jest wartosc EINVAL jesli watek th juz zostal odlaczony (detached) lub inny watek juz oczekuje na jego zakonczenie albo wartosc EDEADLK jesli argument th odnosi sie do wolajacego watku.

  15. odlaczenie dzialajacego watku
  16. pthread_detach

    Deklaracja

    #include <pthread.h>

    int pthread_detach(pthread_t th);

    Opis

    Funkcja pthread_detach odlacza wolajacy watek, co gwarantuje zwolnienie zasobow pamieci natychmiast po zakonczeniu dzialania watku, jednak do odlaczonego watku nie mozna dolaczyc po jego zakonczeniu (pthread_join).

    Watek od razu prze tworzeniu moze byc okreslony jako odlaczony przez ustawienie odpowiedniego atrybutu przy wolaniu pthread_create.

    Jesli funkcja pthread_detach zostanie wywolana w momencie, kiedy jakis watek juz czeka na zakonczenie wywolujacego watku, zostanie on w stanie umozliwiajacym dolaczenie (odlaczenie nie zostanie wykonane).

    W razie powodzenia zwracane jest 0, EINVAL w przypadku bledu, co oznacza, ze watek th zostal juz wczesniej odlaczony.

  17. jednokrotna inicjalizacja
  18. pthread_once

    Deklaracja

    #include <pthread.h>

    pthread_once_t once_control = PTHREAD_ONCE_INIT;

    int pthread_once(pthread_once_t *once_control, void

    (*init_routine) (void));

    Opis

    Wywolanie funkcji pthread_once daje pewnosc, ze inicjalizacja będzie wykonana tylko co najwyzej raz. Argument once_control wskazuje na zewnetrzna zmienna statycznie zainicjalizowana do wartosi PTHREAD_ONCE_INIT.

    Pierwsze wywolanie pthread_once z danym argumentem once_control powoduje wykonanie kodu bezargumentowej procedury init_routine i zmienia wartosc zmiennej once_control zeby zaznaczyc, ze inicjalizacja byla wykonana. Kolejne wywolania pthread_once z tym samym argumentem once_control będą pustymi wywolaniami.

    Funkcja pthread_once zawsze zwraca 0.

  19. rejestracja funkcji, ktore maja sie wykonac przy wywolaniu fork()
  20. pthread_atfork

    Deklaracja

    #include <pthread.h>

    int pthread_atfork(void (*prepare)(void), void (*parent)(void),

    void (*child)(void));

    Opis

    Funkcja pthread_atfork rejestruje funkcje obslugi do wywolania zaraz przed i zaraz po stworzeniu nowego procesu za pomoca funkcji fork. Funkcje przekazane jako prepare beda wykonane przez proces ojca zaraz przed wykonaniem fork, natomiast funkcje podane przez parameter parent zaraz po podziale procesu. Funkcje przekazane argumentem child wykonane zostana przez proces potomny tuz przed powrotem z funkcji fork.

    Kazdy z argumentow funkcji pthread_atfork moze byc ustawiony na NULL, co oznacza puste wywolanie zamiast funkcji

    Funkcja pthread_atfork moze byc wywolywana wielokrotnie w celu zainstalowania wiecej niz jednego zbioru funkcji obslugi. W momencie wykonania fork funkcje prepare wykonywane sa w kolejnosci LIFO, zas parent

    i child w kolejnosci FIFO.

    Zeby zrozumiec przyczyne istnienia funkcji pthread_atfork warto przypomniec, ze w fork duplikuje cala pamiec procesu wlacznie z mutexami razem z ich stanem blokady, za to w procesie potomnym dziala jedynie jeden watek (wolajacy fork). Jesli wiec mutex byl zajety przez watek inny niz wolajacy fork, to zostanie zablokowany na zawsze (w procesie potomnym), co może spowodowac blokade calego procesu potomnego. Zeby tego uniknac należy instalowac funkcje obslugi jak nastepuje: funkcje prepare zajmuja globalne mutexy (w kolejnosci zajmowania), nastepnie funkcje parent i child zwalniaja je (w odwrotnej kolejnosci). Ewentualnie prepare i parent moga być ustawione na NULL podczas, gdy child powinien wywolac pthread_mutex_init na globalnych mutexach.

    Funkcja pthread_atfork zwraca 0 w przypadku sukcesu lub blad ENOMEM, gdy nie ma wystarczajaco duzo pamieci dostepnej zeby zarejestrowac funkcje obslugi.