Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <signal.h>
- int process_num; // Numer procesu (1,2,3)
- int pids[2]; // Każdy proces przetrzymuje pidy dwóch pozostałych procesów
- int queue; // Kolejka komunikatów
- int fd_pipe1[2]; // Tworzymy potok 1
- int fd_pipe2[2]; // Tworzymy potok 2
- int fd_pipe3[2]; // Tworzymy potok 3
- int resumed = 0; // Po otrzymaniu sygnału ustawiamy na 1, aby wyświetlić drugi raz tej samej wiadomości
- // SYGNAŁY
- int S1 = SIGINT; // Zakończenie działania procesów
- int S2 = SIGUSR1; // Zatrzymanie działania procesów
- int S3 = SIGCONT; // Przywrócenie działania procesów
- int S4 = SIGUSR2; // Powiadomienie pozostałych procesów o odebranym sygnale
- int sprawdzPoprawnosc(char text[1000])
- {
- // Długość tekstu - 1 (ostatni jest pusty znak '\0', więc go pomijamy)
- int length = strlen(text)-1;
- int i = 0;
- int czyLiczba = 0;
- // Sprawdzamy czy ostatni znak jest cyfrą, jeżeli nie to od razu zwracamy 0
- if(!isdigit(text[length-1])) return 0;
- // W pętli przechodzimy po każdym znaku
- for(i; i < length; i++)
- {
- // Jeżeli nie było wcześniej żadnej cyfry i odczytany znak nie jest cyfrą to zwracamy 0
- if(czyLiczba == 0 && !isdigit(text[i])) return 0;
- // Jeżeli odczytany znak to '+', ustawiamy zmienną czyLiczba na 0
- if(text[i] == '+') czyLiczba = 0;
- // Jeżeli odczytany znak jest cyfrą to ustawiamy czyLiczba na 1
- else if(isdigit(text[i])) czyLiczba = 1;
- // Jeżeli żaden z powyższych warunków nie został spełniony
- // to znaczy że odczytano inny znak niż '+' i cyfrę
- // a więc nie spełnia to wymagań i zwracamy 0
- else return 0;
- }
- // Jeżeli funkcja nie zwróciła 0, to znaczy, że przesłany ciąg jest poprawny
- return 1;
- }
- unsigned long policzLinie(char text[1000])
- {
- // Długość tekstu - 1 (ostatni jest pusty znak '\0', więc go pomijamy)
- int length = strlen(text)-1;
- // i - przechodzenie po kolejnych znakach
- // j - przechodzenie po buforze dla odczytywanej liczby
- int i = 0, j = 0;
- // bufor, który będziemy konwertować na int i dodawać do sumy
- char num_bufor[12];
- // ustawiamy zmienną suma na 0
- unsigned long suma = 0;
- // przechodzimy po wszystkich znakach linii
- for(i; i < length; i++)
- {
- // jeżeli wcześniej nie było cyfry i odczytany znak nie jest cyfrą
- // to ciąg jest nieprawidłowy i zwracamy 0
- if(j == 0 && !isdigit(text[i])) return 0;
- // jeżeli odczytany znak to '+'
- if(text[i] == '+')
- {
- // dodajemy znak pusty na koniec bufora
- num_bufor[j] = 0;
- // konwertujemy bufor znaków na int i dodajemy do sumy
- suma += atoi(num_bufor);
- // resetujemy indeks od jakiego zapisujemy znaki do bufora
- j = 0;
- }
- // jeżeli nie został odczytany '+' to znaczy, że odczytano cyfrę
- // dodajemy ją do bufora i inkrementujemy j
- else num_bufor[j++] = text[i];
- }
- // gdy doszło do końca znaków to ustawiamy kolejny znak jako pusty
- num_bufor[j] = 0;
- // konwertujemy bufor na int i dodajemy do sumy
- suma += atoi(num_bufor);
- // zwracamy obliczoną sumę linii
- return suma;
- }
- /* --------------------------------------- */
- /* Struktura i funkcje kolejki komunikatów */
- /* --------------------------------------- */
- struct message {
- // Typ wiadomości (adresowanie do danego procesu)
- long type;
- // Przesyłany tekst
- char text[1000];
- };
- int msg_utworz()
- {
- // Generowanie klucza
- int key = ftok(".", 100);
- // Tworzenie kolejki komunikatów
- int queue = msgget(key, IPC_CREAT | 0666);
- // Zwracanie id kolejki komunikatów
- return queue;
- }
- int msg_usun(int queue)
- {
- // Usuwanie kolejki komunikatów
- msgctl(queue, IPC_RMID, NULL);
- }
- /* --------------------------------------- */
- /* Obsługa sygnałów */
- /* --------------------------------------- */
- void killProcess()
- {
- // Wypisujemy który proces kończy swoje działanie
- fprintf(stderr, "KILL %d\n", process_num);
- if(process_num == 1)
- {
- // Zamykamy pipe 1
- close(fd_pipe1[0]);
- close(fd_pipe1[1]);
- }
- else if(process_num == 2)
- {
- // Zamykamy pipe 2
- close(fd_pipe2[0]);
- close(fd_pipe2[1]);
- }
- else if(process_num == 3)
- {
- // Zamykamy pipe 3
- close(fd_pipe3[0]);
- close(fd_pipe3[1]);
- // Usuwamy kolejkę komunikatów
- msg_usun(queue);
- }
- exit(0);
- }
- void stopProcess()
- {
- // Wyświetla który proces zatrzymujemy
- fprintf(stderr, "STOP %d\n", process_num);
- // Tworzymy maskę sygnałów
- sigset_t mask;
- // Wypełniamy maskę (ignorujemy wszystkie sygnały)
- sigfillset(&mask);
- // Usuwamy z maski sygnał S3 (sygnał ten będzie mógł wznowić pracę procesu)
- sigdelset(&mask, S3);
- // Usuwamy z maski sygnał S4 (sygnał ten będzie mógł wznowić pracę procesu)
- sigdelset(&mask, S4);
- // Robimy suspend (proces teraz czeka na sygnał S3 lub S4)
- sigsuspend(&mask);
- }
- void resumeProcess()
- {
- // ustawiamy resumed na 1,
- resumed = 1;
- // Wyświetlamy, który proces został wznowiony
- fprintf(stderr, "RESUME %d\n", process_num);
- }
- void sigAction(int signum)
- {
- // W zależności od otrzymanego sygnału jaka funkcja ma się wykonać
- if(signum == S1) killProcess();
- else if(signum == S2) stopProcess();
- else if(signum == S3) resumeProcess();
- }
- void handleSig(int signum)
- {
- /* ---------------------------------------------- */
- /* Obsługa sygnału przez proces, który go odebrał */
- /* ---------------------------------------------- */
- // Zapisanie numeru sygnału do pipe pozostałych procesów
- if(process_num != 1) write(fd_pipe1[1], &signum, sizeof(int));
- if(process_num != 2) write(fd_pipe2[1], &signum, sizeof(int));
- if(process_num != 3) write(fd_pipe3[1], &signum, sizeof(int));
- // Powiadamiamy pozostałe procesy o sygnale
- kill(pids[0], S4);
- kill(pids[1], S4);
- // Wykonujemy odpowiednią funkcję dla otrzymanego sygnału
- sigAction(signum);
- }
- void sigMessage(int signum)
- {
- // Po otrzymaniu Si4 odczytujemy z pipe numer sygnału
- // Każdy proces ma swój osobny potok, w którym adresowane są do niego przesłane sygnały
- int sig;
- if(process_num == 1) read(fd_pipe1[0], &sig, sizeof(int));
- if(process_num == 2) read(fd_pipe2[0], &sig, sizeof(int));
- if(process_num == 3) read(fd_pipe3[0], &sig, sizeof(int));
- // Przesyłamy odczytany sygnał do funkcji sigAction
- sigAction(sig);
- }
- /* WYMIANA PIDAMI PROCESÓW */
- void wymiana_pidami(int *queue)
- {
- // Tworzenie wiadomości i wysłanie swojego pida pozostałym procesom
- struct message m;
- // Konwertujemy pid procesu na tekst i zapisujemy go w polu text wiadomości
- sprintf(m.text, "%d", getpid());
- int i = 1;
- // Przechodzimy w pętli przez wartości 1,2,3
- for(i; i < 4; i++)
- {
- // Jeżeli aktualny numer w pętli jest równy numerowi procesu
- // to przechodzimy do kolejnego kroku pętli
- if(i == process_num) continue;
- // Ustawiamy typ wiadomości na wartość i (adresujemy wiadomość do pozostałych procesów)
- m.type = i;
- // Wysyłamy wiadomość w kolejce komunikatów
- msgsnd(*queue, &m, sizeof(m), 0);
- }
- // Odebranie pidów pozostałych procesów
- msgrcv(*queue, &m, sizeof(m), process_num, 0);
- // Konwersja odczytanego pida w postaci stringa na inta i zapisanie w zmiennej globalnej
- pids[0] = atoi(m.text);
- msgrcv(*queue, &m, sizeof(m), process_num, 0);
- pids[1] = atoi(m.text);
- }
- /* --------------------------------------- */
- /* Proces 1 */
- /* Odczytuje dane ze standardowego wejścia */
- /* i przekazuje je w niezmienionej formie */
- /* do procesu numer 2 */
- /* --------------------------------------- */
- void proces1()
- {
- struct message m;
- // Ustawienie typu wiadomosci na 2 (adresowanie do drugiego procesu)
- m.type = 2;
- while(fgets(m.text, 1000, stdin) != NULL)
- {
- // Wysyłamy odczytany z stdina tekst kolejką komunikatów
- msgsnd(queue, &m, sizeof(m), 0);
- // Pozostałe procesu potrzebują trochę czasu
- // na sprawdzenie poprawności danych i policzenie sumy
- // więc aby nie przepełnić kolejki czekamy 5ms
- usleep(5000);
- }
- m.text[0] = EOF;
- msgsnd(queue, &m, sizeof(m), 0);
- close(fd_pipe1[0]);
- close(fd_pipe1[1]);
- }
- /* ---------------------------------------- */
- /* Proces 2 */
- /* Pobiera dane i sprawdza ich poprawność */
- /* ---------------------------------------- */
- void proces2()
- {
- // Tworzymy zmienną do odczytania wiadomości
- struct message m;
- // Odbiera wiadomość o typie 2 do zmiennej m
- while(msgrcv(queue, &m, sizeof(m), 2, 0))
- {
- // Ustawiamy typ wiadomości na 3 (adresowanie do procesu 3)
- m.type = 3;
- // Jeżeli został wysłany EOF to wysyłamy go do procesu 3 i kończymy pracę
- if(m.text[0] == EOF)
- {
- msgsnd(queue, &m, sizeof(m), 0);
- break;
- }
- // Po otrzymaniu sygnału wznawiającego proces "przeskakuje" oczekiwanie na wiadomość
- // i nie wysyłamy drugi raz poprzedniej wiadomości
- if(resumed)
- resumed = 0;
- // Sprawdzamy czy otrzymane dane mają poprawny format
- // Jeżeli tak to przesyłamy do procesu 3
- else if(sprawdzPoprawnosc(m.text))
- msgsnd(queue, &m, sizeof(m), 0);
- }
- close(fd_pipe2[0]);
- close(fd_pipe2[1]);
- }
- /* ---------------------------------------- */
- /* Proces 3 */
- /* Pobiera dane z procesu 2 i wylicza sumę */
- /* wyrażenia, następnie obliczoną sumę */
- /* umieszcza w standardowym strumieniu */
- /* wyjściowym */
- /* ---------------------------------------- */
- void proces3()
- {
- // Tworzy zmienną na odebraną wiadomość
- struct message m;
- // Odbiera wiadomość o typie 3 do zmiennej m
- while(msgrcv(queue, &m, sizeof(m), 3, 0))
- {
- // Jeżeli odczytało EOF to kończy działanie
- if(m.text[0] == EOF) break;
- // Po otrzymaniu sygnału wznawiającego pracę proces "przeskakuje"
- // przez odebranie kolejnej wiadomości, więc nie wyświetlamy wyniku obliczeń
- if(resumed)
- resumed = 0;
- else
- printf("%ld\n", policzLinie(m.text));
- }
- close(fd_pipe3[0]);
- close(fd_pipe3[1]);
- msg_usun(queue);
- }
- void proces(int i)
- {
- process_num = i;
- // Obsługa sygnałów
- signal(S1, handleSig);
- signal(S2, handleSig);
- signal(S3, handleSig);
- signal(S4, sigMessage);
- // Tworzenie kolejki komunikatów
- queue = msg_utworz();
- // Zapisanie pidów pozostałych procesów
- wymiana_pidami(&queue);
- if(i == 1) proces1();
- else if(i == 2) proces2();
- else if(i == 3) proces3();
- exit(0);
- }
- int main()
- {
- // Tworzymy 3 potoki dzięki którym będziemy wysyłać
- // numery odebranych sygnałów
- pipe(fd_pipe1);
- pipe(fd_pipe2);
- pipe(fd_pipe3);
- if(fork() == 0)
- proces(1);
- else if(fork() == 0)
- proces(2);
- else if(fork() == 0)
- proces(3);
- // Czekamy aż procesy zakończą swoją pracę
- wait(NULL);
- wait(NULL);
- wait(NULL);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement