LEKCJA21.TXT

(14 KB) Pobierz
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...
Zgłoś jeśli naruszono regulamin