Projekt sprawozdanie doc


Treść zadania indywidualnego:

  1. Opracować zestaw programów typu producent-konsument realizujących przy wykorzystaniu mechanizmu kolejek komunikatów, następujący schemat komunikacji międzyprocesowej:

Proces 1: czyta dane (pojedyncze wiersze) ze standardowego strumienia wejściowego i przekazuje je w niezmienionej formie do procesu 2.

Proces 2: pobiera dane przesyłane przez proces 1. Szyfruje odebrane dane przy pomocy dowolnego prostego algorytmu i przekazuje do procesu 3.

Proces 3: pobiera dane wyprodukowane przez proces 2 i umieszcza je w standardowym strumieniu wyjściowym. Każda odebrana jednostka danych powinna zostać wyprodukowana w osobnym wierszu.

  1. Należy zaproponować i zaimplementować mechanizm informowania procesów o swoim stanie. Należy wykorzystać do tego dostępny mechanizm sygnałów i łączy komunikacyjnych (pipes). Wszystkie trzy procesy powinny być powoływane automatycznie z jednego procesu inicjującego.

Zaimplementować mechanizm asynchronicznego przekazywania informacji pomiędzy operatorem a procesami oraz pomiędzy procesami. Wykorzystać do tego dostępny mechanizm sygnałów i łączy komunikacyjnych (pipes).

Operator może wysyłać do dowolnego procesu sygnał zakończenia działania (S1), sygnał wstrzymania działania (S2) i sygnał wznowienia działania (S3). Sygnał S2 powoduje wstrzymanie synchronicznej wymiany danych pomiędzy procesami. Sygnał S3 powoduje wznowienie tej wymiany. Sygnał S1 powoduje zakończenie działania oraz zwolnienie wszelkich wykorzystywanych przez procesy zasobów.

Każdy z sygnałów przekazywany jest przez operatora tylko do jednego, dowolnego procesu. O tym, do którego procesu wysłać sygnał, decyduje operator, a nie programista. Każdy z sygnałów operator może wysłać do innego procesu. Mimo, że operator kieruje sygnał do jednego procesu, to pożądane przez operatora działanie musi zostać zrealizowane przez wszystkie trzy procesy. W związku z tym, proces odbierający sygnał od operatora musi powiadomić o przyjętym żądaniu pozostałe dwa procesy. Powinien wobec tego wysłać do nich sygnał (S4) oraz przekazać informacje o tym, jakiego działania wymaga operator, przekazując im stosowny komunikat (lub komunikaty) poprzez mechanizm sygnałów i łączy komunikacyjnych (pipes). Procesy odbierające sygnał S4, powinny odczytać skierowany do nich komunikat (lub komunikaty) w procedurze odbierania sygnału S4. Wszystkie trzy procesy powinny zareagować zgodnie z żądaniem operatora.

Sygnały oznaczone w opisie zadania symbolami S1- S4 należy wybrac samodzielnie spośród dostępnych w systemie (np. SIGUSR1, SIGUSR2, SIGINT, SIGCONT).

Zobrazowanie zadania:

0x08 graphic

0x08 graphic

Opis użytych mechanizmów:

Kolejki komunikatów razem z semaforami i pamięcią współdzieloną należą do zaawansowanych urządzeń IPC, które sprawiają, że Unix jest systemem nadzwyczaj bogatym w obszarze komunikacji procesowej.

Cechą charakterystyczną wyżej wymienionych urządzeń są klucze, które są używane do identyfikacji obiektów IPC w systemie. Klucz pozwala na wspólne użycie zasobów IPC przez kilka procesów. Rzeczywisty typ danych klucza jest określony przez zależny od implementacji typ key_t, zdefiniowany w systemowym pliku nagłówkowym <sys/types.h>.

Komunikaty są przekazywane między procesami za pomocą kolejek komunikatów, tworzonych lub udostępnianych przez funkcje pierwotną msgget. Gdy kolejka jest utworzona, proces, mając stosowne uprawnienia kolejki, może umieścić w niej komunikat za pomocą funkcji msgsnd. Inny proces może wtedy odczytać ten komunikat za pomocą funkcji msgrcv, która ponadto usuwa go z kolejki.

Deklaracja: int msgget(key_t key, int permflags);

key :

- identyfikator kolejki

permflags :

- 9 mniej znaczących bitów służy do nadania uprawnień kolejce,

- flaga IPC_CREAT odpowiada za utworzenie kolejki komunikatow dla wartości key, o ile ona jeszcze nie istnieje,

- flaga IPC_EXCL razem z IPC_CREAT przeznaczone SA tylko do utworzenia kolejki komunikatów.

Deklaracja: msgsnd(int mqid, const void* message, size_t size, int flags);

mqid:

- wartość uzyskana z wywołania msgget,

message:

- struktura komunikatu,

size:

- maksymalna długość, która może być trzymana wewnątrz struktury komunikatu,

Flags:

- zawiera informację kontrolna (IPC_NOWAIT i MSG_NOERROR).

Deklaracja: msgrcv(int mqid, void *message, size_t, long msg_type, int flags);

msg_type:

- określa dokładnie, jaki komunikat został właśnie odebrany,

- jeśli jest równy 0, to odczytywany będzie pierwszy komunikat z kolejki, a w przeciwnym wypadku wg priorytetu.

             Procesy komunikują się z jądrem systemu, a także między sobą ,aby koordynować swoją działalność. Linux wspiera kilka mechanizmów komunikacji. Jednym z nich są sygnały, zwane inaczej przerwaniami programowymi.
      Sygnały mogą być generowane bezpośrednio przez użytkownika (funkcja kill()), może wysyłać je jądro oraz procesy między sobą (funkcja systemowa kill()) . Dodatkowo pewne znaki z terminala powodują wygenerowanie sygnałów.  

Sygnały są mechanizmem asynchronicznym - proces nie wie z góry, kiedy sygnał może nadejść i głównym ich zadaniem jest informowanie procesu o zaistnieniu w systemie wyjątkowej sytuacji .

            Sygnały działają jak rodzaj programowego zaworu, który przerywa proces, niezależnie od tego, co on aktualnie robi. Z powodu swojej natury, sygnały SA używane raczej do obsługi nietypowych sytuacji, a nie do prostego przesłania danych pomiędzy procesami.

Sygnał może zrobić z sygnałem następujące trzy rzeczy:

Potok to jeden z prostszych mechanizmów komunikacji międzyprocesowej umożliwiający wymianę danych pomiędzy dwoma procesami. Odbywa się to najczęściej poprzez połączenie standardowego wyjścia jednego procesu ze standardowym wejściem drugiego.

Proces może wysyłać dane „w dół” potoku za pomocą funkcji systemowej write, a inny proces może odebrać dane na drugim końcu potoku, używając funkcji systemowej read.

Wewnątrz programu potok jest tworzony za pomocą funkcji systemowej o nazwie pipe().Jeśli wywołanie było pomyślne, zwraca ona dwa deskryptory plików: jeden do zapisu do potoku, a drugi do odczytu z niego.

Deklaracja: int pipe(int fildes[2]);

fields[0] - deskryptor pliku tylko do odczytu,

fields[1] - deskryptor pliku tylko do zapisu.

Kod programu:

- plik kolejki.h:

//biblioteki

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <unistd.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <string.h>

#include <fcntl.h>

#include "synch.c"

#include <signal.h>

#include <sys/stat.h>

#include <errno.h>

// identyfikatory kluczy kolejek komunikatow

#define KLUCZ_K1 (key_t)1

#define KLUCZ_K2 (key_t)2

// prawa dostepu dla kolejki

#define PRAWA 0660

// maksymalna dlugosc stringu

#define MAX_DL_STR 512

// deklaracja struktury komunikatu

// przekazywanego przez kolejke komunikatow

struct q_entry

{

long mtype;

char mtext[MAX_DL_STR];

};

- plik synch.c:

// definicja listy dostepnych sygnalow

#define S1 SIGUSR1

#define S2 SIGUSR2

#define S3 SIGCHLD

#define S4 SIGALRM

//definicja nazw plikow tworzonych do zapisu PID procesu i identyfikatora kolejki

#define PID_FILE_P1 "p1.pid"

#define PID_FILE_P2 "p2.pid"

#define PID_FILE_P3 "p3.pid"

#define ID_K1_FILE "id_k1"

#define ID_K2_FILE "id_k2"

//funkcja zapisu PID danego procesu do danego pliku

int savePID(int PID, char file[])

{

FILE *fs=fopen(file, "w+");

fprintf(fs, "%d\n", PID);

fclose(fs);

return 0;

}

//funkcja pobierajaca PID danego procesu z danego pliku

int loadPID(char file[])

{

int tmp=0;

FILE *fs=fopen(file, "r");

fscanf(fs, "%d", &tmp);

fclose(fs);

return tmp;

}

//funkcja zapisu identyfikatora danej kolejki komunikatow do danego pliku

int saveID_K(int id, char file[])

{

FILE *fs=fopen(file, "w+");

fprintf(fs, "%d\n", id);

fclose(fs);

return 0;

}

//funkcja pobierajaca identyfikatora danej kolejki komunikatow z pliku

int loadID_K(char file[])

{

int tmp=0;

FILE *fs=fopen(file, "r");

fscanf(fs, "%d", &tmp);

fclose(fs);

return tmp;

}

- plik dane:

komunikat

wprowadzam komunikat

cos

wiadomosc 1

wiadomosc 2

wiadomosc 3

wiadomosc 4

wiadomosc 5

wiadomosc 6

wiadomosc 7

wiadomosc 8

.

.

.

koniec

- plik „P0.c:

#include "kolejki.h"

main()

{

int p1,p2,p3;

int pipe1[2], pipe2[2], pipe3[2];

char wynik_1[12], wynik_2[12], wynik_3[12];

//otwieranie potokow

if(pipe(pipe1) == -1)

{

printf("[P0] Blad przy otwieraniu potoku pipe1\n");

exit(1);

}

if(pipe(pipe2) == -1)

{

printf("[P0] Blad przy otwieraniu potoku pipe2\n");

exit(1);

}

if(pipe(pipe3) == -1)

{

printf("[P0] Blad przy otwieraniu potoku pipe3\n");

exit(1);

}

printf("[P0] PID: %d\n",getpid());

//tworzenie procesow potomnych

if((p1=fork())==0)

{

sprintf(wynik_1, "%d", pipe1[0]); // konwersja lizczby

sprintf(wynik_2, "%d", pipe2[1]); // (deskryptora zapisu lub odczytu potoku)

sprintf(wynik_3, "%d", pipe3[1]); // na lancuch znakowy

// uruchomienie pliku p1 i przekazanie deskryptorow jako parametrow

execl("p1", "p1", wynik_1, wynik_2, wynik_3, NULL);

exit(0);

}

else if(p1==-1)

{

printf("[P0] Blad wywolania fork w procesie o PID: %d\n",getpid());

exit(2);

}

if((p2=fork())==0)

{

sprintf(wynik_1, "%d", pipe1[1]); // konwersja lizczby

sprintf(wynik_2, "%d", pipe2[0]); // (deskryptora zapisu lub odczytu potoku)

sprintf(wynik_3, "%d", pipe3[1]); // na lancuch znakowy

// uruchomienie pliku p2 i przekazanie deskryptorow jako parametrow

execl("p2", "p2", wynik_1, wynik_2, wynik_3, NULL);

exit(0);

}

else if(p2 == -1)

{

printf("[P0] Blad wywolania fork w procesie o PID: %d\n",getpid());

exit(2);

}

if((p3 =fork()) == 0)

{

sprintf(wynik_1, "%d", pipe1[1]); // konwersja lizczby

sprintf(wynik_2, "%d", pipe2[1]); // (deskryptora zapisu lub odczytu potoku)

sprintf(wynik_3, "%d", pipe3[0]); // na lancuch znakowy

// uruchomienie pliku p3 i przekazanie deskryptorow jako parametrow

execl("p3", "p3", wynik_1, wynik_2, wynik_3, NULL);

exit(0);

}

else if(p3 == -1)

{

printf("[P0] Blad wywolania fork w procesie o PID: %d\n",getpid());

exit(2);

}

exit(0);

}

- plik „P1.c”:

//biblioteki

#include "kolejki.h"

#define PLIK "dane"

int PID, flag=0;

int pipeDoMnie, pipe2, pipe3;

int PID_2, PID_3;

int id_k1, id_k2;

// deklaracje funkcji wysyania i odbierania sygnalu, oraz usuwania kolejki

void sygnal(int s);

void sygnalS4(int s);

void usun_kolejke(int id_k);

int main( int argc, char*argv[])

{

if(argc!=4)

{

printf("[P1] Za malo argumentow\n");

exit(1);

}

// konwersja lancucha na liczbe

pipeDoMnie = atoi(argv[1]);

pipe2 = atoi(argv[2]);

pipe3 = atoi(argv[3]);

int id_k1,

dl_ciag,

y;

char ciag[MAX_DL_STR+100],

wejscie[MAX_DL_STR+200];

struct q_entry komunikat;

FILE *fd;

PID=getpid();

// zapis PID do pliku

savePID(PID, PID_FILE_P1);

//wywolanie funkcji signal

signal(S1, sygnal);

signal(S2, sygnal);

signal(S3, sygnal);

signal(S4, sygnalS4);

printf("[P1] PID: %d\n",getpid());

// tworzenie(otwieranie) kolejki komunikatow

if((id_k1=msgget(KLUCZ_K1, IPC_CREAT | PRAWA)) == -1)

{

printf("[P1] Nie udalo sie utworzyc(otworzyc) kolejki\n");

exit(1);

}

saveID_K(id_k1, ID_K1_FILE);

printf("[P1] Dane z pliku\n");

// otwieranie pliku do odczytu

if((fd=fopen(PLIK ,"r")) == NULL)

{

perror("[P1] fopen()");

exit(1);

}

do

{

// wyzerowanie bufora wejsciowego

memset(wejscie, 0, MAX_DL_STR);

// odczytanie linii danych z otwartego pliku i umieszczenie w buforze wejscie

if(fgets(wejscie, MAX_DL_STR, fd)==NULL)

{

printf("Blad fgets\n");

printf("Usuniecie kolejek komunikatow\n");

//popranie identyfikatora drugiej kolejki komunikatow

id_k2=loadID_K(ID_K2_FILE);

//usuwanie kolejek komunikatow

usun_kolejke(id_k1);

usun_kolejke(id_k2);

printf("Wysanie sygnalu SIGKILL do P2 i P3\n");

//pobranie PID innych procesow

PID_2=loadPID(PID_FILE_P2);

PID_3=loadPID(PID_FILE_P3);

//wyslanie SIGKILL do innych procesow

kill(PID_2, SIGKILL);

kill(PID_3, SIGKILL);

exit(1);

}

dl_ciag=strlen(wejscie);

wejscie[dl_ciag-1] = '\0';

printf("[P1] z pliku: '%s' [%d B]\n", wejscie, strlen(wejscie));

komunikat.mtype=1;

memset(komunikat.mtext, 0, MAX_DL_STR);

strcpy(komunikat.mtext, wejscie);

// dodanie komunikatu do kolejki komunikatow

if((y=msgsnd(id_k1, &komunikat, strlen(komunikat.mtext),0)) == -1)

{

printf("[P1] Nie udalo sie wpisac komunikatu do kolejki\n");

exit(1);

}

else

{

printf("[P1] wyslalem: '%s' [%d B]\n", komunikat.mtext, strlen(komunikat.mtext));

}

sleep(3);

//wstrzymanie procesu jesli dostal sygnal S2

while(flag == 1){}

}while(1);

exit(0);

}

void usun_kolejke(int id_k)

{

//usuwanie kolejki komunikatow

if(msgctl(id_k,IPC_RMID,NULL) == -1)

{

printf("Nie moge usunac kolejki komunikatow 1 \n");

exit(1);

}

}

void sygnal(int s)

{

printf("[P1] przechwycilem sygnal %d\n",s);

char kom;

int PID_2, PID_3;

//pobranie PID innych procesow

PID_2=loadPID(PID_FILE_P2);

PID_3=loadPID(PID_FILE_P3);

printf("[P1] Wysylam sygnaly do %d, %d\n", PID_2, PID_3);

// wiadomosc jaka przesyla proces p1 do innych procesow w zaleznosci od otrzymanego sygnalu

switch(s)

{

case S1:

kom = '1';

break;

case S2:

kom = '2';

break;

case S3:

kom = '3';

break;

}

// wysyanie sygnau S4 do pozostaych procesow

if(kill(PID_2, S4) == -1)

printf("[P1] kill error do P2\n");

if(kill(PID_3, S4) == -1)

printf("[P1] kill error do P3\n");

// zapis do potoku wiadomosci o wyslanym sygnale

if(write(pipe2, &kom, 1) < 0)

perror("[P1] write error: ");

if(write(pipe3, &kom, 1) < 0)

perror("[P1] write error: ");

// odpowiedz procesu p1 na sygnal wyslany przez uzytkownika

switch(s)

{

case S1:

printf("[P1] dostalem sygnal S1, wiec koncze dzialanie\n");

//popranie identyfikatorow kolejek komunikatow

id_k1=loadID_K(ID_K1_FILE);

id_k2=loadID_K(ID_K2_FILE);

//usuwanie kolejek komunikatow

usun_kolejke(id_k1);

usun_kolejke(id_k2);

//wyslanie sygnalu SIGKILL do siebie

kill(PID, SIGKILL);

break;

case S2:

printf("[P1] dostalem sygnal S2, wiec wstrzymuje dzialanie\n");

flag=1;

break;

case S3:

printf("[P1] dostalem sygnal S1, wiec wznawiam dzialanie\n");

flag=0;

break;

}

}

void sygnalS4(int s)

{

char c;

// odczytanie wiadomosci o sygnale z potoku

read(pipeDoMnie, &c, 1);

// odpowiedz procesu p1 na sygnal S4

switch(c)

{

case '1':

printf("[P1] sygnal S4 - koniec dzialania\n");

kill(PID, SIGKILL);

break;

case '2':

printf("[P1] sygnal S4 - zatrzymanie\n");

flag=1;

break;

case '3':

printf("[P1] sygnal S4 - wznowienie\n");

flag=0;

break;

}

}

- plik „P2.c”:

//biblioteki

#include "kolejki.h"

int PID, flag=0;

int pipe1, pipeDoMnie, pipe3;

int id_k1, id_k2;

// deklaracje funkcji wysyania i odbierania sygnalu, oraz usuwania kolejki komunikatow

void sygnal(int s);

void sygnalS4(int s);

void usun_kolejke(int id_k);

int main(int argc, char*argv[])

{

if(argc!=4)

{

printf("Za malo argumentow\n");

exit(1);

}

//konwersja lancucha na liczbe

pipe1 = atoi(argv[1]);

pipeDoMnie = atoi(argv[2]);

pipe3 = atoi(argv[3]);

int id_k1, id_k2, dl_kom, i;

struct q_entry komunikat;

PID=getpid();

// zapis PID do pliku

savePID(PID, PID_FILE_P2);

printf("[P2] PID: %d\n", PID);

//wywolanie funkcji signal

signal(S1, sygnal);

signal(S2, sygnal);

signal(S3, sygnal);

signal(S4, sygnalS4);

// otworanie kolejek komunikatow

if((id_k1=msgget(KLUCZ_K1, IPC_CREAT | PRAWA)) == -1)

{

printf("[P2] Nie udalo sie otworzyc kolejki\n");

exit(1);

}

if((id_k2=msgget(KLUCZ_K2, IPC_CREAT | PRAWA)) == -1)

{

printf("[P2] Nie udalo sie utworzyc(otworzyc) kolejki 2\n");

exit(1);

}

saveID_K(id_k2, ID_K2_FILE);

do

{

// wyzerowanie bufora wejsciowego

memset(komunikat.mtext, 0, MAX_DL_STR);

//odczytanie komunikatu z kolejki komunikatow

if((dl_kom=msgrcv(id_k1, &komunikat, MAX_DL_STR, 0, MSG_NOERROR)) == -1)

{

printf("[P2] Nie udalo sie odczytac komunikatu z kolejki\n");

}

else

{

printf("[P2] odczyalem: '%s' [%d B]\n",komunikat.mtext, dl_kom);

//kodowanie pobranego komunikatu

for(i=0; i<dl_kom; i++)

{

komunikat.mtext[i] = komunikat.mtext[i]+1;

}

// dodanie komunikatu do kolejki komunikatow

if(msgsnd(id_k2, &komunikat, strlen(komunikat.mtext),0) == -1)

{

printf("[P2] Nie udalo sie wpisac komunikatu do kolejki\n");

}

else

{

printf("[P2] wyslalem: '%s' [%d B]\n", komunikat.mtext, strlen(komunikat.mtext));

}

}

//wstrzymanie procesu jesli dostal sygnal S2

while(flag == 1){}

}while(1);

exit(0);

}

void usun_kolejke(int id_k)

{

//usuwanie kolejki komunikatow

if(msgctl(id_k,IPC_RMID,NULL) == -1)

{

printf("Nie moge usunac kolejki komunikatow 1 \n");

exit(1);

}

}

void sygnal(int s)

{

printf("[P2] przechwycilem sygnal %d\n",s);

char kom;

int PID_1, PID_3;

//pobranie PID innych procesow

PID_1=loadPID(PID_FILE_P1);

PID_3=loadPID(PID_FILE_P3);

printf("[P2] Wysylam sygnaly do %d, %d\n", PID_1, PID_3);

// wiadomosc jaka przesyla proces p2 do innych procesow w zaleznosci od otrzymanego sygnalu

switch(s)

{

case S1:

kom = '1';

break;

case S2:

kom = '2';

break;

case S3:

kom = '3';

break;

}

//wysyanie sygnau S4 do pozostaych procesow

if(kill(PID_1, S4) == -1)

printf("[P2] kill error do P2\n");

else

printf("[P2] kill -> %d succed \n", PID_1);

if(kill(PID_3, S4) == -1)

printf("[P2] kill error do P3\n");

else

printf("[P2] kill -> %d succed \n", PID_3);

// zapis do potoku wiadomosci o wyslanym sygnale

if(write(pipe1, &kom, 1) < 0)

perror("[P2] write error: ");

if(write(pipe3, &kom, 1) < 0)

perror("[P2] write error: ");

// odpowiedz procesu p2 na sygnal wyslany przez uzytkownika

switch(s)

{

case S1:

printf("[P2] dostalem sygnal S1, wiec koncze dzialanie\n");

//popranie identyfikatorow kolejek komunikatow

id_k1=loadID_K(ID_K1_FILE);

id_k2=loadID_K(ID_K2_FILE);

//usuwanie kolejek komunikatow

usun_kolejke(id_k1);

usun_kolejke(id_k2);

//wyslanie sygnalu SIGKILL do siebie

kill(PID, SIGKILL);

break;

case S2:

printf("[P2] dostalem sygnal S2, wiec wstrzymuje dzialanie\n");

flag=1;

break;

case S3:

printf("[P2] dostalem sygnal S1, wiec wznawiam dzialanie\n");

flag=0;

break;

}

}

void sygnalS4(int s)

{

char c;

// odczytanie wiadomosci o sygnale z potoku

read(pipeDoMnie, &c, 1);

// odpowiedz procesu p2 na sygnal S4

switch(c)

{

case '1':

printf("[P2] sygnal S4 - koniec dzialania\n");

kill(PID, SIGKILL);

break;

case '2':

printf("[P2] sygnal S4 - zatrzymanie\n");

flag=1;

break;

case '3':

printf("[P2] sygnal S4 - wznowienie\n");

flag=0;

break;

}

}

- plik „P3.c”:

//biblioteki

#include "kolejki.h"

int PID, flag=0;

int pipe1, pipe2, pipeDoMnie;

int id_k1, id_k2;

// deklaracje funkcji wysyania i odbierania sygnalu, oraz usuwania kolejki komunikatow

void sygnal(int s);

void sygnalS4(int s);

void usun_kolejke(int id_k);

int main(int argc, char*argv[])

{

if(argc!=4)

{

printf("[P3] Za malo argumentow\n");

exit(1);

}

// konwersja lancucha na liczbe

pipe1 = atoi(argv[1]);

pipe2 = atoi(argv[2]);

pipeDoMnie = atoi(argv[3]);

int id_k2, dl_kom, i;

struct q_entry komunikat;

PID=getpid();

// zapis PID do pliku

savePID(PID, PID_FILE_P3);

printf("[P3] PID: %d\n", PID);

//wywolanie funkcji signal

signal(S1, sygnal);

signal(S2, sygnal);

signal(S3, sygnal);

signal(S4, sygnalS4);

// otworanie kolejki komunikatow

if((id_k2=msgget(KLUCZ_K2, IPC_CREAT | PRAWA)) == -1)

{

printf("[P3] Nie udalo sie otworzyc kolejki\n");

exit(1);

}

do

{

// wyzerowanie bufora wejsciowego

memset(komunikat.mtext, 0, MAX_DL_STR);

//odczytanie komunikatu z kolejki komunikatow

if((dl_kom=msgrcv(id_k2, &komunikat, MAX_DL_STR, 0, MSG_NOERROR)) == -1)

{

printf("[P3] Nie udalo sie odczytac komunikatu z kolejki\n");

}

else

{

//dekodowanie pobranego komunikatu

for(i=0; i<dl_kom; i++)

{

komunikat.mtext[i] = komunikat.mtext[i]-1;

}

printf("[P3] odczyalem: '%s' [%d B]\n",komunikat.mtext, dl_kom);

}

//wstrzymanie procesu jesli dostal sygnal S2

while(flag == 1){}

}while(1);

exit(0);

}

void usun_kolejke(int id_k)

{

//usuwanie kolejki komunikatow

if(msgctl(id_k,IPC_RMID,NULL) == -1)

{

printf("Nie moge usunac kolejki komunikatow 1 \n");

exit(1);

}

}

void sygnal(int s)

{

printf("[P3] przechwycilem sygnal %d\n",s);

char kom;

int PID_1, PID_2;

//pobranie PID innych procesow

PID_1=loadPID(PID_FILE_P1);

PID_2=loadPID(PID_FILE_P2);

printf("[P3] Wysylam sygnaly do %d, %d\n", PID_1, PID_2);

// wiadomosc jaka przesyla proces p3 do innych procesow w zaleznosci od otrzymanego sygnalu

switch(s)

{

case S1:

kom = '1';

break;

case S2:

kom = '2';

break;

case S3:

kom = '3';

break;

}

//wysyanie sygnau S4 do pozostaych procesow

if(kill(PID_1, S4) == -1)

printf("[P3] kill error do P1\n");

else

printf("[P3] kill -> %d succed \n", PID_1);

if(kill(PID_2, S4) == -1)

printf("[P3] kill error do P2\n");

else

printf("[P3] kill -> %d succed \n", PID_2);

// zapis do potoku wiadomosci o wyslanym sygnale

if(write(pipe1, &kom, 1) < 0)

perror("[P3] write error: ");

if(write(pipe2, &kom, 1) < 0)

perror("[P3] write error: ");

// odpowiedz procesu p3 na sygnal wyslany przez uzytkownika

switch(s)

{

case S1:

printf("[P3] dostalem sygnal S1, wiec koncze dzialanie\n");

//popranie identyfikatorow kolejek komunikatow

id_k1=loadID_K(ID_K1_FILE);

id_k2=loadID_K(ID_K2_FILE);

//usuwanie kolejek komunikatow

usun_kolejke(id_k1);

usun_kolejke(id_k2);

//wyslanie sygnalu SIGKILL do siebie

kill(PID, SIGKILL);

break;

case S2:

printf("[P3] dostalem sygnal S2, wiec wstrzymuje dzialanie\n");

flag=1;

break;

case S3:

printf("[P3] dostalem sygnal S1, wiec wznawiam dzialanie\n");

flag=0;

break;

}

}

void sygnalS4(int s)

{

char c;

// odczytanie wiadomosci o sygnale z potoku

read(pipeDoMnie, &c, 1);

// odpowiedz procesu p1 na sygnal S4

switch(c)

{

case '1':

printf("[P3] sygnal S4 - koniec dzialania\n");

kill(PID, SIGKILL);

break;

case '2':

printf("[P3] sygnal S4 - zatrzymanie\n");

flag=1;

break;

case '3':

printf("[P3] sygnal S4 - wznowienie\n");

flag=0;

break;

}

}

- plik „kompilacja”:

gcc -o p0 P0.c

echo ----------------------------------------

gcc -o p1 P1.c

echo ----------------------------------------

gcc -o p2 P2.c

echo ----------------------------------------

gcc -o p3 P3.c

Wynik działania programu:

Część I zadania:

./kompilacja

./p0

0x01 graphic

0x01 graphic

Część II zadania:

W celu sprawdzenia wyniku działania tej części zadania należy dodatkowo otworzyć druga konsolę operatorską .

Na drugiej konsoli operatorskiej przeglądam drzewo procesów poprzez:

pstree -p

Następnie wysyłam sygnały:

Nie ma znaczenia jaki sygnał wyśle do jakiego procesu, ponieważ każdy proces po otrzymaniu danego sygnału zachowuje się tak samo i przesyła wiadomość o sygnale do innych procesów powodując ze zachowują się identycznie jak proces, od którego otrzymały wiadomość o sygnale.

Wynik działania programu obserwuje na pierwszej konsoli operatorskiej.

Konsola I

0x01 graphic

Konsola II

0x01 graphic

0x01 graphic

Po zakończeniu działania programu sprawdzam, czy wszystkie kolejki komunikatów zostały usunięte, a wszystkie procesy zostały zabite poprzez:

- ipcs

- pstree -p

0x01 graphic

0x01 graphic

proces macierzysty P0

proces potomny P1

proces potomny P3

S4

proces potomny P2

S4

S

Zbiór sygnałów:

{S1, S2, S3}

stdin

stdout

UZYTKOWNIK

pobieranie danych

wyświetlanie danych



Wyszukiwarka

Podobne podstrony:
sprawozdanie doc
ProjektUnifikacja sprawozdanie Nieznany
projekt sprawozdanie
Projekt sprawozdanie
Informatyczne Podstawy Projektowania sprawozdanie
Projekt-sprawozdanie
Projekt-sprawozdanie
Projekt-sprawozdanie
Projekt 1 Sprawozdanie
CUR projekt? SPRAWOZDANIE
Projekt sprawozdanie id 399569 Nieznany
Projekt+Sprawozdanie, WZMACNIACZ TRANZYSTOROWY, PAŃSTWOWA WYŻSZA SZKOŁA ZAWODOWA W ELBLĄGU
plyny tunele, Sprawozdania i projekty, Sprawozdania
projekt1, SPRAWOZDANIA czyjeś
Projekt wału doc
GTG projekt 3 - sprawozdania polroczna i kwartalne, FIR UE Katowice, SEMESTR VI, gieldy, gieldy 1, G
bd2 projekt SprawozdanieAndrzej
539659072 PL 0 0 Mechpl mikromanometry sprawozdanie doc

więcej podobnych podstron