Krótki kurs programowania współbie˙znego (2)
Transkrypt
Krótki kurs programowania współbie˙znego (2)
Krótki kurs programowania współbieżnego (2)
• Procesy i sygnały w j˛ezyku C (to było ostatnio)
• Wspólny dost˛ep do plików (to też)
• Semafory i pami˛eć dzielona
• Inne metody komunikowania
Kurs systemu UNIX
1
Dzielenie zasobów
• Interfejs programistyczny Uniksa dostarcza nast˛epujacych
˛
mechanizmów:
a) Blokowanie plików (było)
b) Semafory
c) Pami˛eć dzielona
Kurs systemu UNIX
2
Semafory
• Mechanizm koordynacyjny znany nam z systemów operacyjnych.
• Operacje na semaforach sa˛ wykonywane niepodzielnie.
• Przypominamy definicj˛e:
– wait(S) - jeżeli wartość S jest dodatnia to zmniejszyć S, w
przeciwnym przypadku oczekiwać
– signal(S) - jeżeli ktoś czeka na S to go wznawiamy, w
przeciwnym przypadku zwi˛ekszamy S.
Kurs systemu UNIX
3
Semafory w Uniksie
• Dość rozbudowany interfejs: wszystkie funkcje operuja˛ na tablicach
semaforów ogólnych.
• Przypomnienie: semafor binarny realizujemy za pomoca˛ semafora
ogólnego przypisujac
˛ mu wartość poczatkow
˛
a˛ równa˛ 1.
• Trzy funkcje zajmuja˛ si˛e obsługa˛ semaforów: semctl, semop,
semget.
• Służa˛ kolejno do sterowania semaforem, do zmiany wartości
semafora oraz do tworzenia semafora.
• Należy właczyć
˛
pliki:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
Kurs systemu UNIX
4
Kurs systemu UNIX
5
Semafory (2)
• Deklaracje
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, size_t nsops);
int semget(key_t key, int nsems, int semflg);
• Parametr key jest liczba˛ całkowita,˛ służac
˛ a˛ do identyfikacji
semaforów pomi˛edzy procesami (coś jak nazwa pliku).
• Operacje na semaforach wykonuje si˛e korzystajac
˛ z identyfikatora
semafora (coś jak deskryptor pliku).
Kurs systemu UNIX
6
Tworzenie semafora
• Funkcja semget tworzy semafor lub zwraca identyfikator już
istniejacego
˛
semafora.
• Można tworzyć semafory „prywatne”, korzystajac
˛ ze specjalnej
wartości parametru key o nazwie IPC_PRIVATE (warto o tym
wiedzieć, by nie użyć tej stałej przypadkowo).
• Kolejnym argumentem jest liczba semaforów w tablicy oraz flagi
(opcje) zwiazane
˛
z semaforem.
• Flagi moga˛ być określajace
˛ dost˛ep (takie jak w funkcji open) oraz
IPC_CREAT; jeżeli zależy nam na nowym, unikatowym semaforze
trzeba dodać IPC_EXCL.
Kurs systemu UNIX
7
Zmiana wartości semafora
• Drugi parametr funkcji semop to wskaźnik na struktur˛e opisujac
˛ a˛
semafor.
• Struktura ta zawiera mi˛edzy innymi nast˛epujace rzeczy:
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
}
• Pierwszy element to numer semafora w tablicy (0 jeżeli jest tylko
jeden).
• Drugi element to wartość, o jaka˛ chcemy zmienić semafor.
Kurs systemu UNIX
8
• Najcz˛eściej używane sa˛ wartości +1 oraz -1, odpowiadajace
˛
poleceniom signal oraz wait.
• Jeżeli flaga SEM_UNDO (w trzecim elemencie) jest właczona,
˛
to
system śledzi zmiany semaforów i zwalnia semafory po zakończeniu
działania procesu.
• Parametr ostatni funkcji semop to liczba semaforów, których dotyczy
operacja.
Kurs systemu UNIX
9
Sterowanie semaforem
• Funkcja semctl pozwala na bezpośrednie sterowanie semaforem.
• Znaczenie parametrów sem_id oraz sem_num takie jak w
poprzednich funkcjach.
• Dwie najcz˛eściej używane komendy:
1) SETVAL – do ustalania wartości semafora (przed pierwszym
użyciem)
2) IPC_RMD – do usuwania semafora.
Kurs systemu UNIX
10
Ustalanie wartości semafora
• Wyst˛epuje wtedy czwarty parametr: wskażnik na unie semun,
zdefiniowana˛ poniżej:
union semun {
int val;
// (...)
}
• W tej unii znajduje si˛e wstawiana wartość.
Kurs systemu UNIX
11
Uproszczony interfejs semaforowy
int create(int key) {
return semget(key, 1, 0666 | IPC_CREAT);
}
void wait(int S) {
sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.flg = SEM_UNDO;
semop(S,&sb,1);
}
void signal(int S) {
//analogicznie, tyle »e
sb.sem_op = +1;
}
Kurs systemu UNIX
12
void delete(int S) {
semctl(S,0,IPC_RMD);
}
void set(int S, int v) {
semun su;
su.val = v;
semctl(S,0,SETVAL, &su);
}
Kurs systemu UNIX
13
Watki
˛ i ich koordynacja w Pythonie
• Podstawowy moduł to threading, który korzysta z
niskopoziomowego modułu thread.
• Przypomnienie: watki
˛ dziela˛ pami˛eć, wykonuja˛ si˛e współbieżnie lub
równolegle.
• Program zakończy działanie, gdy zakończa˛ si˛e wszystkie
„niedemoniczne” jego watki.
˛
Kurs systemu UNIX
14
Tworzenie watków
˛
• Watek
˛ reprezentuje specjalna klasa o nazwie Thread.
• W konstruktorze można podawać argumenty:
– target – obiekt wykonywalny (na przykład funkcja), czyli to, co
watek
˛ b˛edzie robił.
– args – lista argumentów, przekazanych funkcji target
– name – nazwa watku
˛ (sam si˛e jakoś nazwie, jak nie podamy)
• W konstruktorze należy używać przekazywania parametrów za
pomoca˛ słów kluczowych.
• Metoda start uruchomi watek.
˛
Kurs systemu UNIX
15
Zamki (klasa Lock)
• Zamki maja˛ funkcjonalność prostych binarnych semaforów, które
każdy może zamknać
˛ badź
˛ otworzyć.
• acquire może oznaczać zawieszenie watku
˛ (jeżeli zamek jest
zamkni˛ety)
• release oznacza otwarce zamku i być może obudzenie watku
˛
czekajacego.
˛
Kurs systemu UNIX
16
Przykład: filozofowie
#!/usr/local/bin/python
import time,random
from threading import *
def pauza(): time.sleep(3*random.random())
def jedzenie(n):
print n + " zaczyna jedzenie"
pauza()
print n + " ko«czy jedzenie"
def myslenie(n):
print n + " zaczyna my±lenie"
pauza()
print n + " ko«czy my±lenie"
Kurs systemu UNIX
17
def filozof(i,n):
while 1:
L,P = i, (i+1) % 5
W[L].acquire(); W[P].acquire()
jedzenie(n)
W[P].release(); W[L].release()
myslenie(n)
print "Hej, zaczynamy!"
imiona = [ 'Platon', 'Arystoteles', 'Newton', 'Wittgenstein',
'Kubu± Puchatek']
F = []
W = []
Kurs systemu UNIX
18
for i in range(5):
F.append(Thread(target = filozof, args = (i,imiona[i]) ) )
W.add(Lock())
for fil in F:
fil.start()
time.sleep(30)
print "Koniec pracy zarz¡dcy!"
Kurs systemu UNIX
19
Inne możliwości
• Watki
˛ „opóźnione” (klasa Timer)
• Prawdziwe semafory (niekonieczne binarne)
• Wysyłanie sygnałów pomi˛edzy watkami
˛
(Event), możliwe
oczekiwanie.
Kurs systemu UNIX
20
Co moga˛ chronić semafory?
• Pliki (w przypadku wspólnego dost˛epu).
• Pami˛eć dzielona˛ pomi˛edzy różne procesy.
• I wiele innych rzeczy.
Kurs systemu UNIX
21
Pami˛eć dzielona
• Każdy proces ma własna˛ przestrzeń adresowa.˛
• Istnieje możliwość podłaczenia
˛
jednego fragmentu fizycznej pami˛eci
do przestrzeni adresowej wi˛ecej niż jednego procesu.
• Jest to najszybsza metoda komunikacji mi˛edzyprocesowej.
• Ale niestety nie daje żadnych mechanizmów koordynacyjnych —
należy to do programisty (może skorzystać z semaforów).
Kurs systemu UNIX
22
Podstawowe funkcje dotyczace
˛ pami˛eci dzielonej
• shmget – tworzy segment p.d.
• shmat – dołacza
˛ segment p.d. do przestrzeni adresowej procesu.
• shdt – odłacza
˛ pami˛eć od przestrzeni adresowej.
• shmctl – steruje pami˛ecia˛ dzielona.˛
• Pliki nagłówkowe:
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
Kurs systemu UNIX
23
Tworzenie segmentu pami˛eci dzielonej
• Realizujemy funkcja:
˛
int shmget(key_t key, size_t size, int shmflg);
• Idea podobna co w przypadku semaforów, zwraca używany później
identyfikator.
• Flagi ustalaja˛ prawa dost˛epu, można dodatkowo IPC_CREAT
• Mozna zatem tworzyć pami˛eć dzielona˛ taka,˛ która˛ inni tylko czytaja.˛
• Parametr size zawiera wielkość (w bajtach) pami˛eci.
Kurs systemu UNIX
24
Dołaczanie
˛
i odłaczanie
˛
segmentu
• Realizujemy funkcjami:
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(char *shmaddr);
• Pierwszy parametr shmat to identyfikator segmentu, drugi to adres
pod którym chcemy podłaczyć
˛
— najlepiej 0, wówczas system sam
wybierze.
• Funkcja zwraca adres pod którym pami˛eć została podłaczona.
˛
• Przykładowa flaga to SHM_RDONLY sprawiajaca,
˛ że pami˛eć jest tylko
do odczytu.
• Przy odłaczaniu
˛
argumentem jest adres zwrócony przez shmat.
Kurs systemu UNIX
25
Sterowanie
• Realizujemy funkcja:
˛
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
• Znaczenie parametrów: identyfikator pami˛eci, numer komendy i
specjalny bufor zawierajacy
˛ argumenty.
• Możliwe polecenia:
1) IPC_STAT — w trzecim argumencie odczytuje si˛e pewne dane,
zwiazane
˛
z buforem.
2) IPC_RMID — usuwa si˛e segment pami˛eci.
Kurs systemu UNIX
26
Niektóre dane w smid_ds
• Czas ostatnich operacji shmat, shmctl, shmdt.
• PID twórcy, PID procesu, który ostatnio coś robił.
• Ile jest aktualnie dołaczeń.
˛
Kurs systemu UNIX
27
Potoki procesowe
• Jedna z najprostszych metod pozwalajacych
˛
na przekazywanie
danych mi˛edzy procesami.
• Polecenie FILE* popen(char* polecenie,char* tryb)
uruchamia polecenie i umożliwia przekazywanie mu danych za
pomoca˛ operacji plikowych.
• Można również przechwytywać dane wyprodukowane przez inny
proces.
• Tryb musi być równy "r" lub "w" (nie "rw").
• Potok zamykamy poleceniem pclose.
Kurs systemu UNIX
28
Jak sa˛ implementowane potoki z poprzedniego slajdu
• Funkcja pipe stanowi mechanizm niższego poziomu, umożliwiajacy
˛
implementacj˛e (mi˛edzy innymi) polecenia popen.
• Ma nast˛epujac
˛ a˛ sygnatur˛e:
#include <unistd.h>
int pipe(int file_descriptor[2]);
• Zapisujemy do fd[1], a odczytujemy z fd[0].
• Zorganizowane jako kolejka FIFO.
• Umożliwia komunikacj˛e spokrewnionych procesów (dlaczego?).
Kurs systemu UNIX
29
Nazwane potoki
• Umożliwiaja˛ komunikacj˛e pomi˛edzy procesami niespokrewnionymi.
• Można utworzyć potok (skrzynk˛e komunikacyjna)
˛ poleceniem
mkfifo.
• Można wykonać nast˛epujac
˛ a˛ sekwencj˛e poleceń:
mkfifo moje-fifo
cat < moje_fifo &
echo "Tekst do fifo" >> moje_fifo
• Polecenie mkfifo ma swój odpowiednik biblioteczny:
int mkfifo(char *nazwa,int tryb).
Kurs systemu UNIX
30
Używanie nazwanych potoków
• Otwieramy i zamykamy za pomoca˛ funkcji (niskopoziomowych)
open oraz close.
• W opcjach funkcji open możemy dać stała˛ O_NONBLOCK. Wtedy
open zawsze kończy si˛e od razu. W przeciwnym razie po otwarciu
do czytania (O_RDONLY) czeka, aż ktoś otworzy do pisania i
odwrotnie.
• Stała O_NONBLOCK wpływa również nadziałanie funkcji read i
write w przypadku czytania z pustego i pisania do pełnego potoku.
• Uwaga: komunikacj˛e dwustronna˛ najlepiej zrealizować za pomoca˛
dwóch potoków.
Kurs systemu UNIX
31
Kolejki komunikatów — pobieżnie
• Jest to alternatywny mechanizm w stosunku do nazwanych potoków.
• Podobnie jak przy semaforach i pamieci dzielonej kolejk˛e
identyfikuje klucz (liczba całkowita) oraz lokalny identyfikator.
• Funkcje obsługujace
˛ to msgget, msgsnd, msgrcv, msgctl,
zadeklarowane w pliku sys/msg.h.
• Funkcje te zajmuja˛ si˛e otwieraniem, wysyłaniem, odbieraniem oraz
obsługa˛ kolejek komunikatów.
Kurs systemu UNIX
32
Na liście jest zadanie...
• ...napisania prostej aplikacji klient-serwer, wykorzystuacej
˛ różne
mechanizmy komunikacji:
a) semafory + pami˛eć dzielona,
b) nazwane potoki,
c) kolejki komunikatów,
d) gniazda
Kurs systemu UNIX
33