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