1
Mechanizmy komunikacji mi
Mechanizmy komunikacji mi
ę
ę
dzy procesami w
dzy procesami w
standardzie POSIX
standardzie POSIX
•
Przekazywane w formie przerwa
ń
programowych do procesów
•
Informuj
ą
o wyst
ą
pieniu zdarzenia, nie nadaj
ą
si
ę
do przekazywania
danych
•
U
ż
ywane przez j
ą
dro do obsługi sytuacji wyj
ą
tkowych (np. próba
wykonania nielegalnych instrukcji)
•
Obsługa sygnałów
– Podj
ę
cie działa
ń
okre
ś
lonych przez programist
ę
(np. usuwanie plików roboczych)
– Ignorowanie sygnału
– Podj
ę
cie działa
ń
domy
ś
lnych – zwykle zako
ń
czenie procesu (dla SIGUSR
ignorowanie, a SIGSTOP – zawieszenie procesu)
•
Blokowanie sygnałów – wstrzymywanie przyjmowania
(pozostawienie na pó
ź
niej)
•
Wysyłanie sygnałów do innych procesów
Sygna
Sygna
ł
ł
y
y
• Komunikacja mi
ę
dzyprocesowa (IPC – interprocess
communication)
Przyk
Przyk
ł
ł
ady sygna
ady sygna
ł
ł
ó
ó
w
w
Signal name
Description
Default action/effect
SIGABRT
Abnormal termination
Terminate process
SIGALRM
Time-out alarm
Terminate process
SIGCHLD
Change in status of child
Ignore
SIGCONT
Continues stopped process
Ignore
SIGFPE
Floating-point exception
Terminate process
SIGHUP
Hang up
Terminate process
SIGILL
Illegal hardware instruction Terminate process
SIGINT
Terminal interrupt character Terminate process
SIGIO
I/O completion outstanding Ignore
SIGKILL
Termination
Terminate process
(cannot be caught or
ignored)
SIGPIPE
Write to pipe with no readers Terminate process
SIGQUIT
Terminal quit character
Terminate Process
SIGSEGV
Invalid memory reference
Terminate Process
SIGSTOP
Stop process
Stop process (cannot
be caught or ignored)
SIGSYS
Invalid system call
Terminate process
SIGTERM
Software termination
Terminate process
SIGUSR1
User-defined signal
Terminate process
SIGUSR2
User-defined signal
Terminate process
2
Przechwytywanie sygna
Przechwytywanie sygna
ł
ł
u
u
#include <signal.h>
// prosta procedura obsługi sygnału
void obsluga(int signo)
{
printf("\nMam sygnał %d\n", signo);
return;
}
main()
{
static struct sigaction act;
// okre
ś
lenie podejmowanego działania
act.sa_handler = obsluga;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
// przed wywołaniem sigaction, SIGINT powinien zako
ń
czy
ć
proces
sigaction(SIGINT, &act, NULL);
// a teraz ju
ż
nie
while(1) {
printf("Systemy the best!\n");
sleep(1);
}
}
Ignorowanie sygna
Ignorowanie sygna
ł
ł
u
u
#include <signal.h>
main()
{
static struct sigaction act;
// okre
ś
lenie podejmowanego działania
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
// ignorowanie dwóch sygnałów
sigaction(SIGINT, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
while(1) {
printf("Operacyjne the best!\n");
sleep(1);
}
}
3
Przywracanie obs
Przywracanie obs
ł
ł
ugi sygna
ugi sygna
ł
ł
u
u
• Przywracanie poprzedniego działania
main()
{
static struct sigaction act, oact;
// zapami
ę
tanie obsługi sygnału SIGTERM
sigaction(SIGTERM, NULL, &oact);
// ustawienie nowego działania
act.sa_handler = SIG_IGN;
sigaction(SIGTERM, &act, NULL);
.
. Te instrukcje obj
ę
te s
ą
now
ą
obsługa SIGTERM
.
// ju
ż
mo
ż
na przywróci
ć
stare działanie
sigaction(SIGTERM, &oact, NULL);
}
• Przywrócenie domy
ś
lnego działania:
act.sa_handler = SIG_DFL
sigaction(SIGINT, &act, NULL):
Zestawy sygna
Zestawy sygna
ł
ł
ó
ó
w
w
• Przykład:
#include <signal.h>
// deklaracja zmiennych przechowuj
ą
cych zestawy sygnałów
sigset_t mask1, mask2;
// utwórz pusty zestaw
sigemptyset(&mask1);
// dodaj sygnały do zestawu
sigaddset(&mask1, SIGINT);
sigaddset(&mask1, SIGQUIT);
// utwórz pełny zestaw
sigfillset(&mask2);
// usu
ń
sygnał
sigdelset(&mask2, SIGCHLD);
4
Blokowanie sygna
Blokowanie sygna
ł
ł
ó
ó
w
w
• Przykład:
#include <signal.h>
main()
{
sigset_t set1;
sigfillset(&set1);
// ustaw blokad
ę
sigprocmask(SIG_SETMASK, &set1, NULL);
.
. Wykonanie krytycznego kodu
.
// usu
ń
blokad
ę
sigprocmask(SIG_UNBLOCK, &set1, NULL);
}
Wysy
Wysy
ł
ł
anie sygna
anie sygna
ł
ł
ó
ó
w
w
#include <signal.h>
static int alarm_fired = 0;
void alrm_bell(int sig)
{
alarm_fired = 1;
}
int main()
{
int pid;
// utworzenie drugiego procesu
if((pid = fork()) == 0) {
// to robi tylko proces potomny
sleep(5);
// wysłanie sygnału do procesu macierzystego
kill(getppid(), SIGALRM);
exit(0);
}
printf("czekam na alarm\n");
(void) signal(SIGALRM, alrm_bell);
pause();
if (alarm_fired)
printf("Dzy
ń
...Dzy
ń
!\n");
5
Potoki
Potoki
•
Potoki (pipes) umo
ż
liwiaj
ą
jednokierunkow
ą
, asynchroniczn
ą
komunikacj
ę
mi
ę
dzy pokrewnymi procesami (macierzysty/potomny lub maj
ą
cymi
wspólnych przodków).
•
Informacja jest przesy
ł
ana w postaci sekwencyjnego strumienia bajtów,
którego interpretacja nale
ż
y do procesów korzystaj
ą
cych z potoku.
•
Odczytanie informacji powoduje usuni
ę
cie jej z potoku.
•
Je
ż
eli w potoku nie ma tyle informacji, ile chce odczyta
ć
proces-odbiorca, to
jest on wstrzymywany.
•
Przykład 1: Potoki i polecenia konsoli – poł
ą
czenie standardowego wyj
ś
cia i
wej
ś
cia
$ pr doc | lp
•
Alternatywa (bez potoków):
$ pr doc > tmpfile
$ lp < tmpfile
$ rm tmpfile
Potoki
Potoki
-
-
przyk
przyk
ł
ł
ad
ad
#define MSGSIZE 12
char *msg1 = "Systemy ";
char *msg2 = "Operacyjne ";
char *msg3 = "the best ! ";
main() {
char inbuf[MSGSIZE];
int p[2]. j;
pid_t pid;
if (pipe(p) == -1) exit(1); // otwórz potok
pid = fork();// utworzenie procesu potomnego
switch(pid) {
case -1:
exit(2); // nie udało si
ę
utworzy
ć
potomka
case 0:
// to robi potomek
write(p[1], msg1, MSGSIZE);
write(p[1], msg2, MSGSIZE);
write(p[1], msg3, MSGSIZE);
break;
default: // to robi macierzysty
for(j=0; j<3; j++) {
read(p[0], inbuf, MSGSIZE);
printf("%s\n", inbuf);
}
6
Potoki nazwane
Potoki nazwane
•
Problemy ze zwykłymi potokami:
– współpraca tylko procesów pokrewnych
– nietrwało
ść
- wymagaj
ą
działania obu procesów
•
Potoki nazwane (named pipes) inaczej potoki FIFO
•
Przykład: Producent
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)
int main()
{
int pipe_fd;
int res;
int bytes_sent = 0;
char buffer[BUFFER_SIZE + 1];
// utworzenie potoku FIFO je
ż
eli nie istnieje
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) exit(EXIT_FAILURE);
}
pipe_fd = open(FIFO_NAME, O_WRONLY);
if (pipe_fd != -1) {
while(bytes_sent < TEN_MEG) {
res = write(pipe_fd, buffer, BUFFER_SIZE);
if (res == -1) exit(EXIT_FAILURE);
bytes_sent += res;
}
close(pipe_fd);
}
else exit(EXIT_FAILURE);
}
Potoki nazwane c.d
Potoki nazwane c.d
• Przykład cd.: Konsument
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
int main()
{
int pipe_fd;
int res;
char buffer[BUFFER_SIZE + 1];
int bytes_read = 0;
memset(buffer, '\0', sizeof(buffer));
pipe_fd = open(FIFO_NAME, O_RDONLY);
if (pipe_fd != -1) {
do {
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes_read += res;
} while (res > 0);
close(pipe_fd);
}
else exit(EXIT_FAILURE);
}
7
Przekazywanie komunikat
Przekazywanie komunikat
ó
ó
w
w
#include <sys/msg.h>
#define QKEY
(key_t)0105
// klucz dla kolejki
#define QPERM
0660
// prawa dost
ę
pu dla kolejki
// takie elementy b
ę
d
ą
w kolejce
struct q_entry
{
long mtype;
char mtext[50];
}
void main() {
int queue_id;
// utworzenie kolejki
queue id = msgget(QKEY, IPC_CREAT | QPERM);
// przygotowanie komuniatu
struct q_entry s_entry={1, "Pozdrowienia!");
// wysłanie komunikatu
msgsnd(queue_id, &s_entry, 50, 0);
// odebranie komunikatu z kolejki
msgrcv(queue_id, &s_entry, 50, 0, 0);
}
Us
Us
ł
ł
ugi zdalne
ugi zdalne
•
Usługa jest jednostk
ą
oprogramowania działaj
ą
c
ą
na jednej lub wielu maszynach,
pozwalaj
ą
c
ą
korzysta
ć
z okre
ś
lonych funkcji nieznanemu uprzednio klientowi
•
System obsługi (serwer) jest to oprogramowanie usługowe wykonywane na jednej
maszynie
•
Klientem nazywa si
ę
proces wywołuj
ą
cy usług
ę
za pomoc
ą
zbioru operacji zwanym
interfejsem klienta
•
Usługa zdalna jest wywoływana przez klienta za po
ś
rednictwem sieci na zdalnym
serwerze. Wyniki jej działania s
ą
przekazywane przez sie
ć
z powrotem do klienta.
•
Zdalne wywoływanie procedur (Remote Procedure Call – RPC) jest najcz
ęś
ciej
spotykan
ą
metod
ą
realizacji usługi zdalnej
•
Klasyczne podej
ś
cie: ka
ż
da procedura ma na stałe przypisany, znany klientowi numer portu
•
Dynamiczne wi
ą
zanie portu i klienta
s.o. klienta
klient
matchmaker
1
2
3
demon RPC
4
5
6
1 – wywołanie procedury RPC
2 – żądanie numeru portu
procedury
3 – odpowiedź z numerem portu
4 – wysłanie komunikatu do
danego portu z wywołaniem
procedury
5 – realizacja procedury i
odesłanie wyników
6 – przekazanie wyników do
klienta