Zadanie 6 (podsumowujace) ========================= UWAGA: Sposob obliczania wyrazen przedstawiony ponizej nie jest zalecany ****** w rzeczywistych zastosowaniach - koszt tworzenia nowych procesow jest bardzo duzy. Napisz program "oblicz", ktorego zadaniem bedzie obliczanie w sposob rownolegly wyrazen klasycznej arytmetyki zbudowanych za pomoca binarnych operatorow +, -, *, /, % (znaczenie jak w C) i stalych liczbowych typu int. Wywolanie programu: oblicz nazwa_pliku Gdzie plik "nazwa_pliku" zawiera wyrazenie zapisane w zwyklej notacji polskiej w specjalnej formie. Zwykla notacja polska, to notacja prefiksowa bez nawiasow, np.: + * 1 2 - 7 8 to znaczy +(*(1, 2), -(7, 8)) czyli (1 * 2) + (7 - 8) Zwroc uwage, ze w zwyklej notacji polskiej, znajac liczbe argumentow kazdego operatora, nie potrzebujemy nawiasow. Plik wejsciowy sklada sie z pewnej liczby wierszy; kazdy wiersz zawiera jeden element wyrazenia (operator lub liczbe). Dodatkowo w wierszu, w ktorym znajduje sie operator, po pewnej niezerowej liczbie odstepow zapisana jest pozycja w pliku wejsciowym (numer bajtu !!!), w ktorej rozpoczyna sie drugi argument tego operatora (jest to potrzebne do zrownoleglenia obliczen). Pierwszy bajt w pliku ma numer zero. W pliku "convert.c" jest program, ktory przeksztalca wyrazenia ze zwyklej notacji polskiej na postac opisana powyzej. Pamietaj, ze w Unixie przejscie do nowego wiersza zajmuje tylko jeden bajt! Przykladowy plik wejsciowy (15, 13, 22 to numery odpowiednich bajtow): + 14 * 12 1 2 - 21 7 8 Program oblicz wywoluje (EXEC) program pomocniczy "oblicz1", ktorego argumentami sa nazwa pliku z wyrazeniem i bajt od ktorego nalezy zaczac obliczenia. Zatem pierwsze wywolanie ma postac: "oblicz1 nazwa_pliku 0" Dzialanie kazdego z procesow "oblicz1": 1. Jesli wyrazenie, ktore ma zostac obliczone, jest liczba, to wypisuje ja na standardowe wyjscie i konczy dzialanie. 2. Jesli jest to wyrazenie zlozone (zaczyna sie od operatora), to: - tworzymy nienazwane lacza, za pomoca ktorych bedziemy sie komunikowac z potomkami wyliczajacymi argumenty; - tworzymy dwa nowe procesy, ktorych zadaniem jest wyliczenie argumentow (moze zdarzyc sie, ze nie mozna juz utworzyc nowego procesu i wtedy proces powinien sam wyliczyc wartosc przekazanego wyrazenia). Argumentami wywolania tych procesow bedzie nazwa_pliku z wyrazeniem i odpowiedni numer bajtu poczatkowego. - po otrzymaniu wynikow od procesow potomnych wykonujemy odpowiednie dzialanie i wypisujemy wynik na standardowe wyjscie. - moze sie zdarzyc, ze jednym z wynikow jest zero, wowczas: * jesli dzialaniem do wykonania jest mnozenie, wtedy mamy juz pewnosc jaki bedzie wynik i posylamy sygnal INT do drugiego procesu potomnego, bo wynik jego dzialania jest nieistotny. * jesli do wykonania jest dzielenie (/ lub %) i dzielna wyszla zero, to nie ma sensu liczyc dzielnika i mozna drugiemu potomkowi poslac sygnal INT. * jesli do wykonania jest dzielenie (/ lub %) i dzielnik wyszedl zero, oznacza to blad. Wtedy posylamy procesowi macierzystemu sygnal FPE (Floating Point Exception). (zaniedbaj fakt, ze wynik dzialania programu, moze zalezec od szybkosci wykonania procesow; np. wtedy gdy do wykonania jest dzialanie 0 / 0 - wynikiem bedzie 0 lub sygnal FPE). - proces, ktory przechwyci sygnal INT, przekazuje go swym potomkom, a nastepnie konczy dzialanie. - proces, ktory przechwyci sygnal FPE, przekazuje go swemu procesowi macierzystemu, do potomkow wysyla sygnal INT i konczy dzialanie. Krzysztof Stencel