Projekt SO

WYDZIAŁ CYBERNETYKI

INSTYTUT TELEINFORMATYKI I AUTOMATYKI

PROJEKT
ZALICZENIOWY


Zadanie A9

Prowadzący:

dr inż. Zbigniew Zieliński

Wykonał:

1. Opis zadania

I.

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

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

Proces2: pobiera dane przesyłane przez proces 1. Oblicza ilość znaków w każdej linii i wyznaczoną liczbę przekazuje do procesu 3.

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

II.

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

Należy zaimplementować mechanizm asynchronicznego przekazywania informacji pomiędzy operatorem a procesami oraz pomiędzy procesami. Wykorzystać do tego dostępny mechanizm sygnałów i łączy nazwanych (kolejek FIFO).

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 wysyłać do nich sygnał(S4) oraz przekazać informację o tym jakiego działania wymaga operator, przekazując im stosowny komunikat (lub komunikaty) poprzez mechanizm sygnałów i łączy nazwanych (kolejek FIFO). 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 wybrać samodzielnie spośród dostępnych w systemie (np.: SIGUSR1, SIGUSR2., SIGINT, SIGCONT).

Rys. Schemat przedstawia graficzną prezentację zależności pomiędzy procesami w projekcie.

2.Opis rozwiązania

W programie moim występują trzy procesy, pierwszy proces będzie wczytywał dane z klawiatury, następny wyliczał liczbę znaków a kolejny będzie wyświetlał tą liczbę na klawiaturze. Procesy będą komunikowały miedzy sobą za pomocą kolejek FIFO. Wszystkie procesy będą powołane przez proces 0. Użytkownik będzie mógł wysyłać sygnały. Sygnały będą powoływane za pomocą funkcji SIGNAL i będą oznaczały odpowiednio:

-SIGUSR1 -zakończ

-SIGUSR2 -wstrzymaj

-SIGCONT - wznów

-SIGINT – czytaj

Gdy jakiś proces odbierze dowolny sygnał to następnie wysyła sygnał SIGINT do pozostałych dwóch procesów. Następnie za pomocą kolejki FIFO komunikaty odbiorą wiadomość od procesu który jako pierwszy odebrał sygnał.

Funkcja MKFIFO wykorzystałem na podstawie:

PROTOTYPE: int mkfifo( char * path, mode_t mode );

RETURNS: success :0 error: -1

PARAMETRY:

1. path – nazwa ścieżkowa pliku specjalnego będącego kolejką fifo

2. mode – prawa dostępu do łącza

Funkcja OPEN wykorzystałem na podstawie:

PROTOTYPE: int open ( char *path, int flags);

RETURNS: success : deskryptor kolejki FIFO error: -1

PARAMETRY:

1. path – nazwa ścieżkowa pliku specjalnego będącego kolejką fifo

2. mode – prawa dostępu do łącza

3. flags – określenie trybu w jakim jest otwierana kolejka:

O_RDONLY – tryb tylko do odczytu

O_WRONLY– tryb tylko do zapisu

Do komunikacji miedzy procesami wykorzystałem łącza nazwane (kolejki FIFO). Warunkiem wykorzystania łącz nazwanych było istnienie wspólnego przodka procesów. W moim programie był nim proces 0 który powołał: proces1, proces2 i proces3. Do zastosowanie kolejek FIFO konieczne jest dołączenie bibliotek <sys/types.h> oraz <sys/stat.h>. Główną cześć jest: int mkfifo(const char *pathname, mode_t mode). Funkcja ta tworzy kolejkę FIFO o zadanej nazwie i ścieżce (pathname). Argument mode skonstruowałem dokładnie tak samo jak w funkcji open. Funkcja mkfifo zwraca 0 w wypadku sukcesu, a w wypadku niepowodzenia zwraca -1 oraz ustawia zmienną errno na kod odpowiedniego błędu.

Gdy utworzę kolejkę za pomocą funkcji mkfifo mogę ją otworzyć za pomocą funkcji open, a następnie zapisywać do niej za pomocą funkcji systemowych (write, read). Kończąc pracę z kolejką zamykam ją funkcją close (jeśli otwieraliśmy ją open). Czyli traktuje kolejkę FIFO jak zwykły plik. Do kolejek FIFO mogą pisać lub czytać jeden lub więcej procesów

Kolejnym mechanizmem, który wykorzystałem w swoim programie był mechanizm sygnałów. Sygnały są to przerwania programowe procesu. Mogą być one generowane przez jądro systemu operacyjnego lub przez inny proces. Nadejście sygnału jest równoważne z pojawieniem się wyjątkowego zdarzenia które musi być natychmiast obsłużone. Sposoby reakcji na sygnał mogą być różne, decyduje o tym funkcja SIGNAL(). Pierwszy parametr tej funkcji określa sygnał, którego dotyczy wywołanie tej funkcji, a drugi sposób obsługi danego sygnału. Proces może zareagować na sygnał na trzy sposoby: może podjąć akcję standardową (zakończenie procesu, często połączone ze zrzutem pamięci, czasem może wystąpić odrzucenie sygnału) jest wynikiem braku użycia tej funkcji w treści procesu lub przekazania jej wartości SIG_DFL, innym sposobem może być zignorowanie sygnału przez podanie do funkcji SIG_IGN, przechwycenie natomiast występuje gdy funkcji przekazany jest wskaźnik na procedurę obsługi sygnału zdefiniowaną przez programistę, polega ono na wykonaniu tej procedury.

Sygnały których nie można przechwytywać ani ignorować to SIGKILL oraz SIGSTOP

3. Program źródłowy

PMAIN.C:

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <sys/msg.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <signal.h>

static int TheEnd=0;

void TheEndIsNear(){

TheEnd++;

}

int main(){

int PID1,PID2,PID3;

int idkol;

signal(SIGUSR1,TheEndIsNear);

signal(SIGUSR2,TheEndIsNear);

if(mkfifo("fifo",0666)==-1){

perror("tworzenie kolejki fifo nie powiodlo sie\n");

return 0;

}

if(mkfifo("fifo2",0666)==-1){

perror("tworzenie kolejki fifo nie powiodlo sie\n");

return 0;

}

if(mkfifo("fifo3",0666)==-1){

perror("tworzenie kolejki fifo nie powiodlo sie\n");

return 0;

}

if((idkol=msgget(2,IPC_CREAT|0600))==-1){

perror("kolejka komunikatow\n");

return 0;

}

if((PID1=fork())==0){

if(execl("pproc1",(char*)NULL)==-1){

perror("Ladowanie pliku pproc1 nie powiodlo sie\n");

return 0;

}

}else if(PID1==-1){

perror("wystapil blad podczas tworzenia 1 procesu\n");

return 0;

}else{

if((PID2=fork())==0){

if(execl("pproc2",NULL)==-1){

perror("Ladowanie pliku pproc2 nie powiodlo sie\n");

return 0;

}

}else if(PID2==-1){

perror("wystapil blad podczas tworzenia 2 procesu\n");

return 0;

}else{

if((PID3=fork())==0){

if(execl("pproc3",0)==-1){

perror("Ladowanie pliku pproc3 nie powiodlo sie\n");

return 0;

}

}else if(PID3==-1){

perror("wystapil blad podczas tworzenia 3 procesu\n");

return 0;

}else{

while(TheEnd<2){}

msgctl(idkol,IPC_RMID,NULL);

remove("fifo");

remove("fifo2");

remove("fifo3");

}

}

}

}

PPROC1.C:

#include <stdio.h>

#include <sys/msg.h>

#include <sys/ipc.h>

#include <sys/types.h>

#include <string.h>

#include <signal.h>

#include <sys/stat.h>

#include <fcntl.h>

static int robie=1;

static int koncze=0;

void stop(){

printf("PROCES 1:Otrzymałem sygnał aby się wstrzymać\n");

robie=0;

}

void go(){

printf("PROCES 1:Otrzymałem sygnał aby się wznowić\n");

robie=1;

}

void destroy(){

int kolid;

printf("PROCES 1:otrzymałem sygał by sie zabic\n");

koncze=1;

}

void zakoncz(){

int i,j;

char b[2]="1";

kill(getpid()+1,SIGINT);

kill(getpid()+2,SIGINT);

i=open("fifo2",O_WRONLY);

write(i,b,2);

close(i);

j=open("fifo3",O_WRONLY);

write(j,b,2);

close(j);

destroy();

}

void wstrzymaj(){

int i,j;

char b[2]="2";

kill(getpid()+1,SIGINT);

kill(getpid()+2,SIGINT);

i=open("fifo2",O_WRONLY);

write(i,b,2);

close(i);

j=open("fifo3",O_WRONLY);

write(j,b,2);

close(j);

stop();

}

void wznow(){

int i,j;

char b[2]="3";

kill(getpid()+1,SIGINT);

kill(getpid()+2,SIGINT);

i=open("fifo2",O_WRONLY);

write(i,b,2);

close(i);

j=open("fifo3",O_WRONLY);

write(j,b,2);

close(j);

go();

}

void czytaj(){

printf("PROCES 1:Otrzymałem sygnał by czytać z kolejki FIFO\n");

int i,j;

char buf[2];

i=open("fifo",O_RDONLY);

read(i,buf,2);

close(i);

j=atoi(buf);

if(j==1)destroy();

if(j==2)stop();

if(j==3)go();

}

struct KolKom{

long mtyp;

char a[128];

int i;

}kolejka;

int main(void){

int kolid;

char b[128];

kolejka.i=0;

kolejka.mtyp=1;

kolid = msgget(2,0600);

signal(SIGUSR1,zakoncz);

signal(SIGUSR2,wstrzymaj);

signal(SIGCONT,wznow);

signal(SIGINT,czytaj);

if(kolid==-1){

perror("bload przy dolaczaniu sie do juz istniejacej kolejki, proces pierwszy\n");

return 0;

}

while(koncze==0){

if(robie==1){

fflush(stdin);

gets(b);

strcpy(kolejka.a,b);

msgsnd(kolid,&kolejka,sizeof(kolejka),0);

}

}

kill(getppid(),SIGUSR1);

return 0;

}

PPROC2.C:

#include <stdio.h>

#include <sys/msg.h>

#include <sys/ipc.h>

#include <sys/types.h>

#include <string.h>

#include <signal.h>

#include <sys/stat.h>

#include <fcntl.h>

static int robie=1;

static int koncze=0;

void stop(){

printf("PROCES 2:Otrzymałem sygnał aby się wstrzymać\n");

robie=0;

}

void go(){

printf("PROCES 2:Otrzymałem sygnał aby się wznowić\n");

robie=1;

}

void destroy(){

printf("PROCES 2:otrzymałem sygał by sie zabic\n");

koncze=1;

}

void zakoncz(){

int i;

char b[2]="1";

kill(getpid()+1,SIGINT);

i=open("fifo3",O_WRONLY);

write(i,b,2);

close(i);

kill(getpid()-1,SIGINT);

i=open("fifo",O_WRONLY);

write(i,b,2);

close(i);

destroy();

}

void wstrzymaj(){

int i;

char b[2]="2";

kill(getpid()+1,SIGINT);

i=open("fifo3",O_WRONLY);

write(i,b,2);

close(i);

kill(getpid()-1,SIGINT);

i=open("fifo",O_WRONLY);

write(i,b,2);

close(i);

stop();

}

void wznow(){

int i;

char b[2]="3";

kill(getpid()+1,SIGINT);

i=open("fifo3",O_WRONLY);

write(i,b,2);

close(i);

kill(getpid()-1,SIGINT);

i=open("fifo",O_WRONLY);

write(i,b,2);

close(i);

go();

}

void czytaj(){

printf("PROCES 2:Otrzymałem sygnał by czytać z kolejki FIFO\n");

int i,j;

char buf[2];

i=open("fifo2",O_RDONLY);

read(i,buf,2);

close(i);

j=atoi(buf);

if(j==1)destroy();

if(j==2)stop();

if(j==3)go();

}

struct KolKom{

long mtyp;

char a[128];

int i;

}kolejka;

int main(void){

int kolid,j,cont;

char *b;

signal(SIGUSR1,zakoncz);

signal(SIGUSR2,wstrzymaj);

signal(SIGCONT,wznow);

signal(SIGINT,czytaj);

if((kolid=msgget(2,0600))==-1){

perror("blad przy otwieraniu kolejki komuniaktow proces2\n");

return 0;

} while(koncze==0){

if(robie==1){

kolejka.i=0;

cont=msgrcv(kolid,&kolejka,512,1,0);

j=strlen(kolejka.a);

if(cont==-1){

kolejka.i=-1;

kolejka.mtyp=2;

}else{

kolejka.i=j;

kolejka.mtyp=2;

}

msgsnd(kolid,&kolejka,sizeof(kolejka),0);

}

}

return 0;

}

PPROC3.C:

#include <stdio.h>

#include <sys/msg.h>

#include <sys/ipc.h>

#include <sys/types.h>

#include <string.h>

#include <signal.h>

#include <fcntl.h>

static int robie=1;

static int koncze=0;

void stop(){

printf("PROCES 3:Otrzymałem sygnał aby się wstrzymać\n");

robie=0;

}

void go(){

printf("PROCES 3:Otrzymałem sygnał aby się wznowić\n");

robie=1;

}

void destroy(){

printf("PROCES 3:otrzymałem sygał by sie zabic\n");

koncze=1;

}

void zakoncz(){

int i;

char b[2]="1";

kill(getpid()-2,SIGINT);

i=open("fifo",O_WRONLY);

write(i,b,2);

close(i);

kill(getpid()-1,SIGINT);

i=open("fifo2",O_WRONLY);

write(i,b,2);

close(i);

destroy();

}

void wstrzymaj(){

int i;

char b[2]="2";

kill(getpid()-2,SIGINT);

i=open("fifo",O_WRONLY);

write(i,b,2);

close(i);

kill(getpid()-1,SIGINT);

i=open("fifo2",O_WRONLY);

write(i,b,2);

close(i);

stop();

}

void wznow(){

int i;

char b[2]="3";

kill(getpid()-2,SIGINT);

i=open("fifo",O_WRONLY);

write(i,b,2);

close(i);

kill(getpid()-1,SIGINT);

i=open("fifo2",O_WRONLY);

write(i,b,2);

close(i);

go();

}

void czytaj(){

printf("PROCES 3:Otrzymałem sygnał by czytać z kolejki FIFO\n");

int i,j;

char buf[2];

i=open("fifo3",O_RDONLY);

read(i,buf,2);

close(i);

j=atoi(buf);

if(j==1)destroy();

if(j==2)stop();

if(j==3)go();

}

struct KolKom{

long mtyp;

char a[128];

int i;

}kolejka;

int main(void){

int kolid;

char b[128];

signal(SIGUSR1,zakoncz);

signal(SIGUSR2,wstrzymaj);

signal(SIGCONT,wznow);

signal(SIGINT,czytaj);

kolejka.mtyp=2;

if((kolid = msgget(2,0600))==-1){

perror("blad przy otwieraniu kolejki komuniaktow proces 3\n");

return 0;

}

while(koncze==0){

if(robie==1){

kolejka.i=-1;

msgrcv(kolid,&kolejka,512,2,0);

if(kolejka.i!=-1){

printf("%d\n",kolejka.i);

}

}

}

kill(getppid(),SIGUSR2);

return 0;

}

4. Przykładowe wyniki

5. Wnioski:

Dla wygodnej realizacji projektu mój program będzie rozbity na 4 pliki. Plik pmain zawiera funkcje a pproc1,2,3 poszczególne procesy.

Pierwszym mechanizmem użytym w moim programie był mechanizm kolejek komunikatów (IPC –Inter Process Communication). Mechanizm ten posłużył mi do komunikacji i synchronizacji działania procesów w obrębie jednego systemu. Przesyła on pakiety informacji (komunikaty) pomiędzy procesami. Komunikaty mogą mieć zawarte informacje o jakimś zdarzeniu lub dane potrzebne procesowi który będzie odbierał ten komunikat. Są one buforowane na zasadzie kolejek FIFO dzięki czemu można je wysyłać w każdym momencie. Komunikaty znajdują się w kolejce do momentu gdy zostaną odebrane przez proces lub kolejka zostanie usunięta z jądra systemu. Proces odbierający komunikat z całej kolejki może to zrobić bez błędu ponieważ każdy komunikat ma określony typ. Dodatkowo komunikaty mają określoną strukturę i określoną długość. Długość komunikatu jest zależna od rozmiaru przesyłanych danych.

Do powołania kolejki komunikatów nie zbędna jest funkcja MSGGET().W skład jej wchodzą dwa parametry: kanał, poprzez który odbywa się komunikacja oraz prawa dostępu do kolejki dla danego procesu. Poprzez wywołanie funkcji zwracany jest identyfikator kolejki komunikatów tylko wtedy gdy uda się odtworzyć kolejkę komunikatów.

Do wysyłania komunikatów służy funkcja MSGSND(), w jej skład wchodzą 4 parametry:

- identyfikator kolejki

-wskaźnik na obszar pamięci, który zawiera wysłany komunikat

-rozmiar przesyłanej treści

-flagę dostępu – 0 lub IPC_NOWAIT – brak oczekiwania na dodanie komunikatu do kolejki

Do odebrania komunikatu służy natomiast funkcja MSGRCV(),ta funkcja zawiera 5 parametrów:

-identyfikator kolejki

-wskaźnik na obszar pamięci, który zawiera wysłany komunikat

-maksymalny rozmiar przesyłanej treści

-typ komunikatu do odebrania

-flagę dostępu – 0, MSG_NOERROR – przyjmowanie komunikatów o rozmiarze

większym od określonego jako maksymalny i ucinanie ich przyodbiorze lub IPC_NOWAIT

– brak oczekiwania na odebranie komunikatu z kolejki


Wyszukiwarka

Podobne podstrony:
Konspekt projektu SO
Projekty OS projekty z so zima 2010
projekty z so 2012
Projekty OS, projekty z so zima 2010
Projekt SO
Systemy Operacyjne, projekty cwiczenie2 so z
Projekt PAB?sorber !! II
Systemy Operacyjne, projekty cwiczenie3 so z
projekt o narkomanii(1)
!!! ETAPY CYKLU PROJEKTU !!!id 455 ppt
Wykład 3 Dokumentacja projektowa i STWiOR
Projekt nr 1piątek
so c4
Projet metoda projektu

więcej podobnych podstron