Programowanie w systemie Linux
Transkrypt
Programowanie w systemie Linux
Programowanie w systemie Linux Jacek Lach Zakład Oprogramowania Instytut Informatyki Politechnika Śląska Plan Jacek Lach. Programowanie w systemie Linux • Procesy • Struktura • Cykl życia • Sygnały • Wątki • Tworzenie • Synchronizacja Procesy Jacek Lach. Programowanie w systemie Linux • Proces • przestrzeń adresowa, wraz z jednym lub więcej wątkami wykonującymi się w tej przestrzeni adresowej i zasobami potrzebnymi do ich wykonania • wykonujący się program • efekt wykonania instrukcji fork() lub clone() • Proces jest obiektem aktywnym • Proces podczas wykonania może znajdować się w różnych stanach Jacek Lach. Programowanie w systemie Linux Struktura opisująca proces include/linux/sched.h struct task_struct /* fragmenty */{ volatile long state; unsigned long flags; volatile long need_resched; long nice; unsigned long policy; int processor; struct task_struct *next_task, *prev_task; pid_t pid; pid_t pgid; struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; unsigned long start_time; uid_t uid, euid, suid, fsuid; } /proc/sys/kernel/threads-max Szeregowanie procesów Jacek Lach. Programowanie w systemie Linux • O(1) • CFS • SCHED_OTHER (100139), SCHED_BATCH, SCHED_IDLE • SCHED_FIFO (099) • SCHED_RR (099) • W Linuxie stosowane jest szeregowanie z wywłaszczeniem • int nice(int inc); • int setpriority(int which, int who, int prio); Jacek Lach. Programowanie w systemie Linux Szeregowanie procesów – cd. ● Priorytet statyczny ● Priorytet dynamiczny ● struktura prio_array: struct prio_array { int nr_active; unsigned long bitmap[BITMAP_SIZE]; struct list_head queue[MAX_PRIO]; } ● ● active expired Jacek Lach. Programowanie w systemie Linux Szeregowanie procesów – cd. 0 . . . n . . . 139 Jacek Lach. Programowanie w systemie Linux Cykl życia procesu • Tworzenie • Wykonywanie • Zakończenie pracy Jacek Lach. Programowanie w systemie Linux Procesy w systemie Linux • Wątki “bezczynne” (ang. idle) • Wątki jądra wynik wykonania kernel_thread() brak pamięci w przestrzeni użytkownika swobodny dostęp do pamięci jądra • Zadania użytkownika wynik wykonania fork() lub clone() Jacek Lach. Programowanie w systemie Linux Tworzenie procesu • pid_t fork(void) Tworzy nowy proces różniący się od procesu rodzica: Numerem PID Wykorzystaniem zasobów (0) Nie dziedziczy blokad i sygnałów • int clone(int (*fn)(void *), void *child_stack, int flags, void *arg) • W systemie Linux wykorzystuje się mechanizm copyonwrite Stany procesu Jacek Lach. Programowanie w systemie Linux • TASK_RUNNING • TASK_INTERRUPTIBLE • TASK_UNINTERRUPTIBLE • TASK_STOPPED • TASK_TRACED • EXIT_ZOMBIE • EXIT_DEAD Zakończenie procesu Jacek Lach. Programowanie w systemie Linux • Proces może zostać zakończony: • przez wywołanie systemowe exit() • po otrzymaniu sygnału kończącego proces • po zaistnieniu warunków wymuszających zakończenie procesu • Proces po zakończeniu staje się procesem “zombie” Jacek Lach. Programowanie w systemie Linux Wymiana kodu procesu int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg , ..., char *const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); Terminal sterujący procesu Jacek Lach. Programowanie w systemie Linux • Przekierowanie wejścia / wyjścia: • FILE *freopen(const char *path, const char *mode, FILE *stream); • int dup(int oldfd); • int isatty(int desc); • char *ttyname(int desc); Jacek Lach. Programowanie w systemie Linux Sygnały • Sygnał zdarzenie wygenerowane przez system lub proces w celu wymuszenia na programie zmiany działania • Sygnały signal(7): • • • • • • • SIGHUP SIGINT SIGQUIT SIGKILL SIGTERM SIGSEGV ... Jacek Lach. Programowanie w systemie Linux Obsługa sygnałów • typedef void (*sighandler_t)(int); • sighandler_t signal(int signum, sighandler_t handler); • int kill(pid_t pid, int sig); • int pause(void); • SIG_IGN, SIG_DFL Obsługa sygnałów cd. Jacek Lach. Programowanie w systemie Linux • int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); • int sigprocmask(int how, *set, sigset_t *oldset); const sigset_t • int sigemptyset(sigset_t *set); • int sigfillset(sigset_t *set); • int sigaddset(sigset_t *set, int signum); • int sigdelset(sigset_t *set, int signum); struct sigaction sa; sa.sa_handler = sighandler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGINT, &sa, 0); Sygnały czasu rzeczywistego Jacek Lach. Programowanie w systemie Linux • Zakres: RTMIN RTMAX • Zastosowanie zależne od aplikacji • Domyślne działanie: zakończenie procesu • Możliwość kolejkowania sygnałów • Gwarantowana kolejność dostarczenia sygnałów • Z sygnałem można związać dodatkowe informacje Przykład #define _GNU_SOURCE #include <fcntl.h> Jacek Lach. Programowanie w systemie Linux #include <signal.h> #include <stdio.h> #include <unistd.h> /* needed to get the defines */ /* in glibc 2.2 this has the needed values defined */ static volatile int event_fd; static void handler(int sig, siginfo_t *si, void *data) { event_fd = si->si_fd; } Przykład Jacek Lach. Programowanie w systemie Linux int main(void) { struct sigaction act; int fd; int fd1, fd2; act.sa_sigaction = handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction(SIGRTMIN, &act, NULL); } fd = open(".", O_RDONLY); fd1 = fd; fcntl(fd1, F_SETSIG, SIGRTMIN); fcntl(fd1, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT); fd = open("/", O_RDONLY); fd2 = fd; fcntl(fd2, F_SETSIG, SIGRTMIN); fcntl(fd2, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT); while (1) { pause(); if (event_fd == fd1) { printf("[.] Zdarzenie\n"); } else if (event_fd == fd2) { printf("[/] Zdarzenie\n"); } } Wątki • Wątek sekwencja instrukcji wykonująca się w ramach procesu Jacek Lach. Programowanie w systemie Linux ● ● Wątek (proces lekki) – podstawowa jednostka wykorzystania procesora Proces ciężki posiada jeden wątek • Wątek posiada własny stos, współdzieli: • • • • zmienne globalne deskryptory plików obsługę sygnałów katalog roboczy Wątki Jacek Lach. Programowanie w systemie Linux kod, dane, pliki (kod), dane, pliki rejestry, stos rejestry stos rejestry stos rejestry stos wątek wątek wątek wątek proces jednowątkowy proces wielowątkowy Wątki cd. Jacek Lach. Programowanie w systemie Linux • Zalety: • mniejszy nakład systemowy związany z utworzeniem wątku • teoretycznie mniejszy nakład związany z przełączaniem wątków • zwiększenie wydajności pracy programów korzystających z operacji we / wy • wyższy poziom interaktywności procesu • łatwa i szybka komunikacja między wątkami • Wady: • zwiększenie liczby wątków nie zawsze powoduje zwiększenie wydajności programu • trudniejsze oprogramowanie / uruchamianie niż w przypadku programów jednowątkowych Typy wątków Jacek Lach. Programowanie w systemie Linux ● Wątki użytkownika – tworzenie i zarządzanie realizowane przez bibliotekę w przestrzeni użytkownika (Pthreads, UIthreads) ● ● ● szybkie jądro nie posiada żadnych informacji na temat wątków (jednoczesna blokada wszystkich wątków w jadrze jednowątkowym) Wątki jądra – tworzone i zarządzane przez jądro systemu operacyjnego (Solaris, Windows, Linux) ● ● z reguły obsługa zajmuje więcej czasu system operacyjny jest w stanie realizować planowanie wątków (wiele procesorów) Jacek Lach. Programowanie w systemie Linux Modele wielowątkowości ● M:1 – wiele do jednego ● M:N – wiele do wielu ● 1:1 – jeden do jednego M:1 ● Jacek Lach. Programowanie w systemie Linux ● Wątki użytkownika odwzorowane są na pojedynczy wątek jądra (jądro widzi 1 proces!) Wykorzystywane w systemach bez wsparcia dla wątków jądra wątki użytkownika J wątek jądra M:N Jacek Lach. Programowanie w systemie Linux ● Watki użytkownika odwzorowane na zbiór wątków jądra wątki użytkownika J J J wątki jądra 1:1 Jacek Lach. Programowanie w systemie Linux ● Każdy z wątków użytkownika odwzorowany na wątek jądra wątki użytkownika J J J J wątki jądra Wątki w systemie Linux Jacek Lach. Programowanie w systemie Linux • LinuxThreads – do glibc 2.4 • NPTL – od glibc 2.3.2 $ getconf GNU_LIBPTHREAD_VERSION NPTL 0.61 $ LD_ASSUME_KERNEL=2.4 getconf \ GNU_LIBPTHREAD_VERSION linuxthreads0.10 Jacek Lach. Programowanie w systemie Linux Wątki w systemie Linux • ./ttn main() pid: 24440, ppid: 24404 thread 0 pid: 24440 ppid: 24404 thread 1 pid: 24440 ppid: 24404 • LD_ASSUME_KERNEL=2.4 ./ttn main() pid: 24444, ppid: 24404 thread 0 pid: 24446 ppid: 24445 thread 1 pid: 24447 ppid: 24445 Jacek Lach. Programowanie w systemie Linux Tworzenie wątku int pthread_create(pthread_t *thread, pthread_attr_t *attr, void* (*start_routine)(void *), void * arg); int pthread_attr_init( pthread_attr_t attr); int pthread_attr_set*(.); int pthread_attr_setdetachstate(.); Kończenie pracy wątku Jacek Lach. Programowanie w systemie Linux • Zakończenie funkcji wątku • Wywołanie funkcji pthread_exit() przez wątek • Wykonanie funkcji pthread_cancel() na wątku: • pthread_setcancelstate() • PTHREAD_CANCEL_ENABLE / PTHREAD_CANCEL_DISABLE • pthread_setcanceltype() • PTHREAD_CANCEL_ASYNCHRONOUS / PTHREAD_CANCEL_DEFERRED pthread_cleanup_push() / pthread_cleanup_pop() Jacek Lach. Programowanie w systemie Linux Dane prywatne wątków • int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); • int pthread_key_delete(pthread_key_t key); • int pthread_setspecific(pthread_key_t key, const void *pointer); • void *pthread_getspecific(pthread_key_t key); Synchronizacja wątków Jacek Lach. Programowanie w systemie Linux • pthread_join() • Mutexy • Warunki • Semafory Jacek Lach. Programowanie w systemie Linux Mutexy • int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); • int pthread_mutex_lock(pthread_mutex_t *mutex)); • int pthread_mutex_trylock(pthread_mutex_t *mutex); • int pthread_mutex_unlock(pthread_mutex_t *mutex); • int pthread_mutex_destroy(pthread_mutex_t *mutex); Warunki Jacek Lach. Programowanie w systemie Linux • int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); • int pthread_cond_signal(pthread_cond_t *cond); • int pthread_cond_broadcast(pthread_cond_t *cond); • int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); • int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); • int pthread_cond_destroy(pthread_cond_t *cond); Jacek Lach. Programowanie w systemie Linux Warunki przykład ... pthread_mutex_lock(&mut); while (x <= y) { pthread_cond_wait(&cond, &mut); } /* operacje na x i y */ pthread_mutex_unlock(&mut); ... ============================================ ... pthread_mutex_lock(&mut); /* modyfikacja x i y */ if (x > y) pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mut); ... Semafory Jacek Lach. Programowanie w systemie Linux • int sem_init(sem_t *sem, int pshared, unsigned int value); • int sem_wait(sem_t *sem); • int sem_trywait(sem_t *sem); • int sem_post(sem_t *sem); • int sem_getvalue(sem_t *sem, int *sval); • int sem_destroy(sem_t *sem);