LEKCJA 21: KILKA PROCESW JEDNOCZENIE. ________________________________________________________________ W trakcie tej lekcji dowiesz si, jak to zrobi, by Twj PC mg wykonywa kilka rzeczy jednoczenie. ________________________________________________________________ Procesy wspbiene. Sprzt, czyli PC ma moliwoci zdecydowanie pozwalajce na techniczn realizacj pracy wielozadaniowej. Nie ma te adnych przeciwskaza, by zamiast koprocesora umoliwi w PC instalacj drugiego (trzeciego) rwnolegego procesora i uprawia na PC powane programowanie wspbiene. Po co? To proste. Wyobra sobie Czytelniku, e masz procesor pracujcy z czstotliwoci 25 MHz (to 25 MILIONW elementarnych operacji na sekund!). Nawet, jeli wzi pod uwag, e niektre operacje (dodawanie, mnoenie, itp.) wymagaj wielu cykli - i tak mona w uproszczeniu przyj, e Twj procesor mgby wykona od kilkuset tysicy do kilku milionw operacji w cigu sekundy. Jeli pracujesz np. z edytorem tekstu i piszesz jaki tekst - znacznie ponad 99% czasu Twj procesor czeka KOMPLETNIE BEZCZYNNIE (!) na nacinicie klawisza. Przecie Twj komputer mogby w tym samym czasie np. i formatowa dyskietk (dyskietka te jest powolna), i przeprowadza kompilacj programu, i drukowa dokumenty, i przeprowadzi defragmentacj drugiego dysku logicznego, itp. itd.. Nawet taka pseudowspbieno realizowana przez DOS, Windows, czy sie jest ofert dostatecznie atrakcyjn, by warto byo przyjrze si mechanizmom PSEUDO-wspbienoci w C i C++. Wspbieno procesw, moe by realizowana na poziomie * sprztowym (architektura wieloprocesorowa), * systemowym (np. Unix, OS/2), * nakadki (np. sieciowej - time sharing, token passing) * aplikacji (podzia czasu procesora pomidzy rne funkcje/moduy tego samego pojedynczego programu). My zajmiemy si tu wspbienoci widzian z poziomu aplikacji. Funkcje setjmp() (ang. SET JuMP buffer - ustaw bufor umoliwiajcy skok do innego procesu) i longjmp() (ang. LONG JuMP - dugi skok - poza modu) wchodz w skad standardu C i w zwizku z tym zostay "przeniesine" do wszystkich kompilatorw C++ (nie tylko Borlanada). Porozmawiajmy o narzdziach. Zaczniemy od klasycznego zestawu narzdzi oferowanego przez Borlanda. Aby zapamita stan przerwanego procesu stosowana jest w C/C++ struktura PSS (ang. Program Status Structure) o nazwie jmp_buf (JuMP BUFfer - bufor skoku). W przypadku wspbienoci wielu procesw (wicej ni dwa) stosuje si tablic zoon ze struktur typu struct jmp_buf TablicaBuforow[n]; Struktura suy do przechowywania informacji o stanie procesu (rejestrach procesora w danym momencie) i jest predefiniowana w pliku SETJMP.H: typedef struct { unsigned j_sp, j_ss, j_flag, j_cs; unsigned j_ip, j_bp, j_di, j_es; unsigned j_si, j_ds; } jmb_buf[1]; Prototypy funkcji: int setjmp(jmp_buf bufor); void longjmp(jmp_buf bufor, int liczba); W obu przypadkach jmp_buf bufor oznacza ten sam typ bufora (niekoniecznie ten sam bufor - moe ich by wiele), natomiast int liczba oznacza tzw. return value - warto zwracan po powrocie z danego procesu. Liczba ta moe zawiera informacj, z ktrego procesu nastpi powrt (lub inn przydatn w programie), ale nie moe by ZEREM. Jeli funkcja longjmp() otrzyma argument int liczba == 0 - zwrci do programu warto 1. Warto cakowita zwracana przez funkcj setjmp() przy pierwszym wywoaniu jest zawsze ZERO a przy nastpnych wywoaniach (po powrocie z procesu) jest rwna parametrowi "int liczba" przekazanemu do ostatnio wywoanej funkcji longjmp(). Przyjrzyjmy si temu mechanizmowi w praktyce. Wyobramy sobie, e chcemy realizowa wspbienie dwa procesy - proces1 i proces2. Proces pierwszy bdzie naladowa w uproszczeniu wymieniony wyej edytor tekstu - pozwoli na wprowadzanie tekstu, ktry bdzie powtarzany na ekranie. Proces drugi bdzie przesuwa w dolnej czci ekranu swj numerek - cyferk 2 (tylko po to, by byo wida, e dziaa). Program gwny wywoujcy oba procesy powinien wyglda tak: ... void proces1(void); void proces2(void); int main(void) { clrscr(); proces1(); proces2(); return 0; } Ale tu nie ma adnej wspbienoci! Oczywicie. Aby zrealizowa wspbieno musimy zadeklarowa bufor na biecy stan rejestrw i zastosowa funkcje setjmp(): #include <setjmp.h> void proces1(void); void proces2(void); jmp_buf bufor1; int main(void) { clrscr(); if(setjmp(bufor1) != 0) proces1(); //Powrt z procesu2 by? proces2(); return 0; } Po wywoaniu funkcji setjmp() zostanie utworzony bufor1, w ktrym zostanie zapamitany stan programu. Funkcja, jak zawsze przy pierwszym wywoaniu zwrci warto ZERO, wic warunek if(setjmp(bufor1) != 0) ... nie bdzie speniony i proces1() nie zostanie wywoany. Program pjdzie sobie dalej i uruchomi proces2(): void proces2(void) { for(;;) { gotoxy(10,20); printf("PROCES 2: "); for(int i = 1; i<40; i++) { printf(".2\b"); delay(5); //UWAGA: delay() tylko dla DOS! } longjmp(bufor1, 1); <--- wr } ____________ t jedynk zwrci setjmp() } Proces 2 bdzie drukowa "biegajc dwjk" (zwolnion przez opnienie delay(5); o pi milisekund), poczym funkcja longjmp() kae wrci z procesu do programu gwnego w to miejsce: int main(void) { clrscr(); if(setjmp(bufor1)) proces1(); <--- tu powrt proces2(); return 0; } Zmieni si tylko tyle, e powtrnie wywoana funkcja setjmp() zwrci tym razem warto 1, zatem warunek bdzie speniony i rozpocznie si proces1(): void proces1(void) { while(kbhit()) { gotoxy(1,1); printf("PROCES1, Pisz tekst: [Kropka - Koniec]"); gotoxy(pozycja,2); znak = getch(); printf("%c", znak); pozycja++; } if(znak == '.') exit (0); } Proces 1 sprawdzi przy pomocy funkcji kbhit() czy w buforze klawiatury oczekuje znak (czy co napisae). Jeli tak - wydrukuje znak, jeli nie - zakoczy si i program przejdzie do procesu drugiego. A oto program w caoci: [P075.CPP] #include <stdio.h> #include <process.h> #include <setjmp.h> #include <conio.h> #include <dos.h> void proces1(void); void proces2(void); jmp_buf bufor1, bufor2; char znak; int pozycja = 1; int main(void) { clrscr(); if(setjmp(bufor1)) proces1(); proces2(); return 0; } void proces1(void) { while(kbhit()) { gotoxy(1,1); printf("PROCES1, Pisz tekst: [Kropka - Koniec]"); gotoxy(pozycja,2); znak = getch(); printf("%c", znak); pozycja++; } if(znak == '.') exit (0); } void proces2(void) { for(;;) { gotoxy(10,20); printf("PROCES 2: "); for(int i = 1; i<40; i++) { printf(".1\b"); delay(5); } longjmp(bufor1,1); } } [!!!] UWAGA ________________________________________________________________ Funkcja delay() uyta dla opnienia i zwolnienia procesw bdzie funkcjonowa tylko w rodowisku DOS. Przy uruchamianiu prykadowego programu pod Windows przy pomocy BCW naley t funkcj poprzedzi znakiem komentzrza // . ________________________________________________________________ Wyobramy sobie, e mamy trzy procesy. Przykad wspbienoci trzech procesw oparty na tej samej zasadzie zawiera program poniej [P076.CPP] #include <stdio.h> #include <process.h> #include <setjmp.h> #include <conio.h> #include <dos.h> void proces1(void); void proces2(void); void proces3(void); jmp_buf bufor1, bufor2; char znak; int pozycja = 1; int main(void) { clrscr(); if(setjmp(bufor1)) proces1(); if(setjmp(bufor2)) proces2(); proces3(); return 0; } void proces1(void) { while(kbhit()) { gotoxy(1,1); printf("PROCES1, Pisz tekst: [Kropka - Koniec]"); gotoxy(pozycja,2); znak = getch(); printf("%c", znak); pozycja++; } if(znak == '.') exit (0); } void proces2(void) { for(;;) { gotoxy(10,20); printf("PROCES 2: "); for(int i = 1; i<40; i++) { printf(".2\b"); delay(5); } longjmp(bufor1, 1); } } void proces3(void) { for(;;) { gotoxy(10,23); printf("PROCES 3: "); for(int i = 1; i<40; i++) { printf(".3\b"); delay(2); } longjmp(bufor2,2); } } Procesy odbywaj si z rn prdkoci. Kolejno uruchamiania procesw bdzie: - proces3() - proces2() - proces1() Po uruchomieniu programu zauwaysz, e proces pierwszy (pisania) zosta spowolniony. Mona jednak temu zaradzi przez ustawienie flag i priorytetw. Jeli dla przykadu uwaamy, e pisanie jest waniejsze, moemy wykrywa zdarzenie - nacinicie klawisza w kadym z mniej wanych procesw i przerywa wtedy procesy mniej wane. Wprowadzanie tekstu w przykadzie poniej nie bdzie spowolnione przez pozostae procesy. [P077.CPP] #include <stdio.h> #in...
Infesto