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 (100­139), SCHED_BATCH, SCHED_IDLE
• SCHED_FIFO (0­99)
• SCHED_RR (0­99)
• 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 copy­on­write
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, UI­threads)
●
●
●
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
linuxthreads­0.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);