Krótki kurs programowania współbieżnego
Transkrypt
Krótki kurs programowania współbieżnego
Krótki kurs programowania współbieżnego • Procesy i sygnały w językach C oraz Python • Semafory i pamięć dzielona (język C) • Uproszczony semafor z Pythona • Inne metody komunikowania Kurs systemu UNIX 1 Ale najpierw dokończenie o curses • Zadanie: opracować przeglądarkę plików graficznych pracującą w trybie tekstowym. • Co się przyda: – Obsługa myszki (opcjonalnie) – Obsługa plików graficznych (koniecznie) Kurs systemu UNIX 2 Myszka • W trybie keypdad funkcja getch może zwrócić stałą KEY_MOUSE... • wówczas możemy dowiedzieć się więcej wywołując getmouse(). • zwrócony wynik to krotka (id,x,y,z,bstate). Znaczenie pól: – id identyfikator urządzenia – x,y,z współrzędne zdarzenia (z nie używany) – bstate stan przycisków myszki i nie tylko w momencie zdarzenia Kurs systemu UNIX 3 Stan przycisków • Stan jest wartością całkowitą, zdefinowane są stałe umożliwiające odczyt poszczególnych bitów, przykładowo: from curses import * ... id,x,y,z,state = getmouse() if state | BUTTON1_DOUBLECLICKED: # było podwójne kliknięcie myszki w punkcie x,y • Inne stałe to (n oznacza liczbę 1,2,3 lub 4): Kurs systemu UNIX BUTTONn_PRESSED -- wciśniety BUTTONn_RELEASED -- zwolniony BUTTONn_CLICKED -- kliknięty BUTTON_SHIFT, BUTTON_ALT, BUTTON_CTRL -dodatkowo wciśnięte odpowiednie klawisze 4 Obsługa plików graficznych • W standardowej dystrybucji na razie ubogo: wsparcie dla plików sgi rgb w module rgbimg • Dobrą opinią cieszy się natomiast Python Imaging Library (PIL), do znalezienia na stronie http://www.pythonware.com/products/index.htm Kurs systemu UNIX 5 Co jest niezbędne? • Czytanie plików >>> import Image >>> im = Image.open("plik.jpg") >>> im.format, im.size, im.mode (JPEG, (250,250), RGB) • Innnym trybem jest L dla obrazów czarno-białych • Dostęp do punktu: im.getpixel(x,y). Jeżeli obiekt ma wiele warstw, to wynikiem jest krotka. Nazwy warstw to krotka zwracana przez im.getbands(), przykładowo (’R’,’G’,’B’). Kurs systemu UNIX 6 A teraz właściwy temat wykładu Kurs systemu UNIX 7 Procesy i sygnały z poziomu powłoki • To był wykład bodajże czwarty. • Polecenie ps informuje o działających procesach. • Polecenie kill wysyła sygnał. • Pamietamy, że kaźdy proces ma swój identyfikator (PID). , Kurs systemu UNIX 8 Podstawowe funkcje dotyczące procesów • Uruchamianie procesu systemowego (system) • Zastępowanie innym procesem (exec) • „Rozdwajanie procesów” (fork) • Nagłówki tych funkcji znajdują się w pliku unistd.h Kurs systemu UNIX 9 Polecenia exec • Dostępnych jest kilka poleceń o nazwach zaczynających się od exec • Polecenie zastępuje bieżący proces innym, tworzonym na podstawie argumentu. • Pierwszym argumentem jest zawsze ścieżka, pod którą można znaleźć program. • Argumenty przekazujemy jako kolejne napisy, zakończone pustym wskaźnikiem execl, albo tablicę wskażników do znaków (execv) • Przykłady: execl("/bin/ps","ps","-ax",0); char *argv[] = { "ps", "-ax", 0 }; execv("/bin/ps", argv); Kurs systemu UNIX 10 • W funkcjach z dodatkowym e w nazwie mamy dodatkowy argument — środowisko, przekazywany tak jak parametr argv. • Przykładowo: char *env[] = { "PATH=/bin:/usr/bin", "TERM=vt100", 0 }; execle("/bin/ps", "/bin/ps","ps","-ax",0, env); Kurs systemu UNIX 11 Duplikowanie procesu • Jest konieczne, jeżeli chcemy, by procesy wykonywały więcej niż jedno zadanie. • Funkcja fork rozdwaja bieżący proces. • Nowy proces wykonuje ten sam kod, ale w innej przestrzeni danych i z własnym środowiskiem. • Ma nowy PID i jego PPID wskazuje na proces rodzica. • W połączeniu z którąś funkcją exec pozwala na „rodzenie” procesów realizujących inne programy. Kurs systemu UNIX 12 Używanie funkcji fork • Deklaracja funkcji fork: #include <sys/types.h> #include <unistd.h> pid_t fork(); • Funkcja fork w procesie macierzystym zwraca PID nowo utworzonego procesu. • Funkcja fork w procesie potomnym zwraca 0. • Możliwy jest też wynik -1 (w procesie macierzystym), oznaczający, że coś poszło nie tak (na przykład przekroczona maksymalna liczba dzieci, czy też brak pamięci w tablicy procesów na nowy wpis). Kurs systemu UNIX 13 Python • Funkcje fork oraz exec* znajdują się w module os. • Oczywiście używają typów Pythona, czyli – Napisów zamiast char* – Listy zamiast char** – Liczb całkowitych zamiast pid_t, etc – Słownika jako środowiska • Nie trzeba dawać 0 jak mamy nieokreśloną liczbę argumentów. Kurs systemu UNIX 14 Przykład #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main() { pid_t pid; char *message; int n; printf("Program fork rozpoczął pracę\n"); pid = fork(); switch(pid) { case -1: perror("Coś nie tak."); Kurs systemu UNIX 15 exit(1); case 0: message = "Proces potomny."; n = 5; break; default: message = "Proces macierzysty."; n = 3; break; } for(; n > 0; n--) { puts(message); sleep(1); } exit(0); } Kurs systemu UNIX 16 Wynik działania programu Program fork rozpoczął pracę To proces macierzysty. To proces potomny. To proces macierzysty. To proces potomny. To proces macierzysty. To proces potomny. swiatowit:prych> To proces potomny. To proces potomny. Kurs systemu UNIX 17 Oczekiwanie na proces potomny • Proces potomny żyje własnym życiem, czasem chcielibyśmy, by rodzic dowiedział się o losie dziecka, by przykładowo, nie działy się takie brzydkie rzeczy jak w ostatnim przykładzie • Oczekiwanie rodzica na dziecko osiągamy wywołując funkcję wait, która wstrzymuje działanie procesu macierzystego do czasu, gdy jeden z procesów potomnych zakończy działanie. • Deklaracja: #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *stat_loc) • Zwraca kod ukończonego procesu, więcej można się dowiedzieć za pomocą makr odczytujących zawartość zapisaną pod adresem stat_loc Kurs systemu UNIX 18 • Przykładowo WEXITSTATUS(*stat_loc) zwraca kod wyjściowy procesu potomnego. Kurs systemu UNIX 19 Funkcje związane z sygnałami • Sygnał można wysłać (kill), można również zdecydować, w jaki sposób należy sygnał obsłużyć (signal). • Można ponadto wysłać sygnał do samego siebie (raise), można na sygnał poczekać (pause). • Funkcja alarm umożliwia wysłanie za jakiś czas sygnału SIGALRM. • Deklaracje: #include <signal.h> #include <sys/types.h> int kill(pid_t pid,int sig) int raise(int sig) #include <unistd.h> unsigned int alarm(unsigned int liczba-sekund) Kurs systemu UNIX 20 Deklaracja funkcji signal • Deklaracja funkcji signal jest nieco skomplikowana: #include <signal.h> void (*signal(int sig, void (*func)(int)))(int) • Deklaracja mówi, że funkcja signal bierze dwa parametry: sig (numer sygnału) oraz func — wskaźnik na funkcję, która wymaga jednego argumentu całkowitego. Argumentem dla funkcji func jest numer sygnału, który ma obsłużyć. • Funkcja signal zwraca wartość tego samego typu, co func i jest to poprzednia wartość funkcji obsługującej ten sygnał. • Można używać dwóch specjalnych stałych: SIG_IGN – ignoruj sygnał oraz SIG_DFL – obsługa domyślna. • Jeżeli coś pojdzie źle, to funkcja signal może zwrócić stałą Kurs systemu UNIX 21 SIG_ERR. Kurs systemu UNIX 22 Aplikacja budzika #include <signal.h> #include <stdio.h> #include <unistd.h> static int alarm_fired = 0; void ding(int sig) {alarm_fired = 1;} int main() { int pid; printf("Budzik działa\n"); if((pid = fork()) == 0) { sleep(5); Kurs systemu UNIX 23 kill(getppid(), SIGALRM); exit(0); } printf("Czekamy\n"); (void) signal(SIGALRM, ding); pause(); if (alarm_fired) printf("Dzyń, dzyń!\n"); printf("Gotowe\n"); exit(0); } Kurs systemu UNIX 24 Sygnały w Pythonie • Moduł signal. • Zdefiniowanie reakcji dla sygnału to signal(s,reakcja), przy czym reakcja musi się dać wykonać dla dwóch argumentów: numeru sygnału oraz ramki definiującej zmienne (frame object). • Funkcja kill(proces,syg) jest w modle os. • Funkcja pause jest w module signal. Kurs systemu UNIX 25 Dzielenie zasobów • Interfejs programistyczny Uniksa dostarcza następujących mechanizmów: 1. Blokowanie plików 2. Semafory 3. Pamięć dzielona Kurs systemu UNIX 26 Blokowanie plików • Najprostszy schemat (blokowania kooperacyjnego) zakłada wykluczające tworzenie plików — flag, mówiących o tym, że czegoś robić nie wolno. • Realizuje się to za pomocą niskopoziomowej operacji open z flagami: O_RDWR | O_CREAT | O_EXCL • Uzyskujemy w ten sposób gwarancję, że tylko jednemu procesowi uda się utworzyć blokadę. • Całą resztę należy zaprogramować samodzielnie. Kurs systemu UNIX 27 Blokowanie obszarów • W przypadku korzystania przez wiele procesów z bardzo dużych plików schemat z poprzdniego slajdu jest niewystarczający. • System dostarcza mechanizmu blokowania obszarów w pliku. • Relizuje się to za pomocą funkcji fcntl używanej zgodnie z następującą sygnaturą: #include <fcntl.h> int fcntl(int desPliku, int polecenie, struct flock*); • Struktura flock powinna zawierać między innymi pola: short short off_t off_t pid_t l_type; l_whence; l_start; l_len; l_pid; Kurs systemu UNIX // F_RDLCK, F_UNLCK, F_WRLCK 28 Dalsze szczegóły • Stałe F_RDLCK, ... oznaczają rodzaj blokady (lub informację że chcemy zdjąć blokadę) • Są dwa rodzaje blokady: czytelnika (blokuje pisarzy) oraz pisarza (blokuje wsystkich). • Obszar pliku definiujemy za pomocą pól l_start oraz l_len, określających początek obszaru i jego długość. • Miejsce, od którego liczymy początek określone jest parametrem l_whence. Możliewe są trzy wartości: 1. SEEK_SET: od początku 2. SEEK_CUR: od bieżącej pozycji 3. SEEK_END: od końca Kurs systemu UNIX 29 Drugi parametr: polecenie • Interesują nas trzy wartości dla polecenia: 1. F_GETLK — odczytywanie blokady (na zadanym obszarze) 2. F_SETLK — ustawianie blokady 3. F_SETLKW — cierpliwe ustawianie blokady: ja się nie udaje to czekamy. • W każdy z tych wywołań określamy jaka blokada nas interesuje. Po wywołaniu GET trzeba sprawdzić, czy coś zmieniiło się w strukturze przekazanej jako trzeci argument: jeżeli tak to pole l_pid wskazuje na blokujący proces, natomiast pozostałe pola to nowa informacja o tej blokadzie, która uniemożliwiła nasze blokowanie. • Polecenie GET nie blokuje pliku. Kurs systemu UNIX 30 Jeszcze o blokowaniu • Zaleca się używanie blokowania z operacjami read oraz write. • Ich odpowiedniki z biblioteki standardowej korzystają z własnych buforów, co może spowodować nieprawdłowe działanie. • Do użytkownika należy zapobieganie zakleszczeniom. • Istnieje prostsza (acz mniej ogólna) funkcja blokująca: lockf. Kurs systemu UNIX 31