SOISK - SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE
Tomasz Puchała

LAB3

 

Instrukcja laboratoryjna nr 3

ZADANIE: Zapoznaj się z przykładowym programem ex2.c demonstrującym sposób przekazywania parametrów do funkcji wątków oraz zasadę synchronizacji poprzez sekcje krytyczne. Napisz program, który pobiera od użytkownika 20 liczb (zapisując je w zmiennej tablicowej), tworzy dwa wątki i przesyła do nich (jako parametry ich funkcji) po połowie tablicy. Wątki sortują otrzymane połówki tablicy, informują program/wątek główny o zakończeniu swojej pracy, zaś ten wyświetla posortowane połówki, następnie scala je w jedną posortowaną całość i ją wyświetla. Do synchronizacji wątków roboczych z wątkiem głównym użyj obiektów sekcji krytycznych.


 

Synchronizacja sekcją krytyczną

oprac. Robert Tomaszewski

Program przykładowy ex2.c

/* Program demonstrujący użycie obiektu sekcji krytycznej do synchronizacji wątków.

Obsługa sekcji krytycznej obejmuje następujące kroki/funkcje:

1) Deklaracja obiektu sekcji

2) Zainicjowanie obiektu, przydział zasobów - InitializeCriticalSection

3) Próba przejęcia obiektu, wejścia do sekcji krytycznej (jeśli nieudana to

wątek zawiesi się do czasu powodzenia operacji - EnterCriticalSection

4) Opuszczenie sekcji krytycznej (ktoś inny może do niej wejść, przejąć

obiekt sekcji - LeaveCriticalSection

5) Zniszczenie obiektu sekcji, uwolnienie zasobów - DeleteCriticalSection

*/

#include <windows.h>

#include <stdio.h>

/* Definicja typu strukturalnego i typu wskaźnikowego na strukturę */

typedef struct

{

char napis[10];

int liczba;

} TPARAM, *PTPARAM;

/* Deklaracja obiektu sekcji krytycznej - można stworzyć kilka obiektów */

CRITICAL_SECTION sekcja;

/* Funkcja wątku */

DWORD WINAPI proc(LPVOID arg)

{

int i,licznik1=0; /* prywatne dane wątku */

PTPARAM parametr; /* zmienna na parametr przekazany do wątku - u nas struktura */

/* Próba wejścia do sekcji krytycznej */

EnterCriticalSection(&sekcja);

for (i=0;i<10;i++)

{

++licznik1;

printf("WATEK w sekcji krytycznej: licznik watku: %dn",licznik1);

}

parametr = (PTPARAM) arg; /* przypisanie argumentu do zmiennej prywatnej */

printf("Parametr watku:%s, %un",parametr->napis,parametr->liczba++);

/* Opuszczenie obiektu sekcji krytycznej */

LeaveCriticalSection(&sekcja);

}

int main(void)

{

TPARAM zm; /* tą zmienną przekażemy do funkcji wątków */

DWORD id;

int licznik=0;

/* Wypełnienie pól struktury */

printf("Wpisz jakis tekst (do 10 znakow):");

scanf("%s",zm.napis);

printf("A teraz liczbe calkowita dodatnia:");

scanf("%u",&zm.liczba);

/* Zainicjowanie obiektu sekcji krytycznej */

InitializeCriticalSection(&sekcja);

/* Utworzenie wątku - bez zapamiętania uchwytu */

if (CreateThread(NULL,0,proc,&zm,0,&id) != NULL)

printf("Watek utworzony!n");

/* Program/wątek główny też coś robi */

for (licznik=0;licznik<=5;licznik++)

printf("PROGRAM: Licznik globalny programu: %dn",licznik);

printf("Program czeka na wejscie do sekcji krytycznej...n");

/* Wątek główny czeka za zakończenie wątku potomnego – zwolnienie sekcji krytycznej */

EnterCriticalSection(&sekcja);

printf("Parametr watku (zmieniony przez watek):%s, %un",zm.napis,zm.liczba);

LeaveCriticalSection(&sekcja);

DeleteCriticalSection(&sekcja);

system("PAUSE");

return 0;

}

Program przykładowy ex3.c

/* Poniższy program został zaczerpnięty z witryny WWW Microsoftu (MSDN) i demonstruje

nieprawidłowe wykorzystanie obiektów sekcji krytycznej - następuje w nim zakleszczenie

*/

#include <windows.h>

#include <stdio.h>

CRITICAL_SECTION cs1,cs2; /* deklaracja dwóch obiektów sekcji krytycznej */

/* Prototyp funkcji */

DWORD WINAPI ThreadFn(LPVOID);

int main(void)

{

DWORD iThreadID;

InitializeCriticalSection(&cs1);

InitializeCriticalSection(&cs2);

/* Zwróć uwagę na poniższy, oryginalny sposób utworzenia wątku – nie będziemy

potrzebować uchwytu, więc od razu go zwalniamy – TO NIE ZABIJA WĄTKU! Powoduje

jedynie, że nie możemy skorzystać z funkcji wątkowych wymagających podania HANDLE */

CloseHandle(CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFn,NULL,0,&iThreadID));

while(TRUE){

EnterCriticalSection(&cs1);

printf("nWatek1 jest w sekcji 1, ale nie w 2.");

EnterCriticalSection(&cs2); /* moment potencjalnego zakleszczenia! */

printf("nWatek1 jest w sekcji 1 i 2!");

LeaveCriticalSection(&cs2);

printf("nWatek1 opuscil sekcje 2, ale jest w sekcji 1.");

LeaveCriticalSection(&cs1);

printf("nWatek1 opuscil obie sekcje krytyczne...");

Sleep(20);

};

return(0);

}

/* Funkcja wątku – będzie rywalizować z wątkiem głównym o obiekty sekcji krytycznej */

DWORD WINAPI ThreadFn(LPVOID lParam)

{

while(TRUE)

{EnterCriticalSection(&cs2);

printf("nWatek2 jest w sekcji 2, ale nie w 1.");

EnterCriticalSection(&cs1); /* moment potencjalnego zakleszczenia! */

printf("nWatek2 jest w sekcji 2 i 1!");

LeaveCriticalSection(&cs1);

printf("nWatek2 opuscil sekcje 1, ale jest w sekcji 2.");

LeaveCriticalSection(&cs2);

printf("nWatek2 opuscil obie sekcje krytyczne...");

Sleep(20);

};

}

ZADANIE: Zapoznaj się z przykładowym programem ex2.c demonstrującym sposób przekazywania parametrów do funkcji wątków oraz zasadę synchronizacji poprzez sekcje krytyczne. Napisz program, który pobiera od użytkownika 20 liczb (zapisując je w zmiennej tablicowej), tworzy dwa wątki i przesyła do nich (jako parametry ich funkcji) po połowie tablicy. Wątki sortują otrzymane połówki tablicy, informują program/wątek główny o zakończeniu swojej pracy, zaś ten wyświetla posortowane połówki, następnie scala je w jedną posortowaną całość i ją wyświetla. Do synchronizacji wątków roboczych z wątkiem głównym użyj obiektów sekcji krytycznych.

Wskazówka:

W przypadku, gdyby wątek główny zyskiwał dostęp do sekcji krytycznych przed wątkami roboczymi można uśpić (funkcją Sleep, tuż przed EnterCriticalSection) na krótko wątek główny, aby upewnić się, że planista procesów w systemie operacyjnym umożliwi wątkom wejście do sekcji krytycznych przed wątkiem głównym. PRZYDATNE ŹRÓDŁA:

Opis wątków i procesów w Windows (interesują nas tylko wątki - threads): http://msdn2.microsoft.com/en-us/library/ms684841.aspx

Pisanie programów wielowątkowych w Windows:

http://msdn2.microsoft.com/en-us/library/y6h8hye8(VS.71).aspx

Synchronizacja wielobieżności w programach Windows (interesują nas sekcje krytyczne, semafory i zdarzenia

– critical section, semaphores, events)

http://msdn2.microsoft.com/en-us/library/ms686353.aspx

Opisy biblioteczne funkcji i struktur używanych w programowaniu wielowątkowym:

http://msdn2.microsoft.com/en-us/library/aa908719.aspx



_____________________________________________________________



 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h> 
int tab[20];
int tab1[10];
int tab2[10];
int i,min,max;
void bubblesort( int tab[], int n ) 
{
  int i,j;
  int tmp;
  int change;
 
  for (i=0; i<n-1; ++i) 
  {
       change=0;
       for (j=0; j<n-1-i; j++)
          if (tab[j+1] < tab[j])
          {  
              tmp = tab[j];      
              tab[j] = tab[j+1];
              tab[j+1] = tmp;         
              change=1;
          }
       if(!change) break;      
  }
}

void bubblesort2( int tab[], int n ) 
{
  int i,j;
  int tmp;
  int change;
 
  for (i=0; i<n-1; ++i) 
  {
       change=0;
       for (j=0; j<n-1-i; j++)
          if (tab[j+1] < tab[j])
          {  
              tmp = tab[j];      
              tab[j] = tab[j+1];
              tab[j+1] = tmp;         
              change=1;
          }
       if(!change) break;      
  }
}

int main(int argc, char *argv[])
{
    srand( (unsigned)time( NULL ) );
  printf("Podaj 20 liczbn");
for (i=0 ; i<=20 ; i++)
{
  printf("Podaj liczbe %d ",i);
  scanf("%d",&tab[i]);
  //rand() >> tab[i];

}
for(i=0 ; i<=20 ; i++){
   if (i<=10){
              tab1[i]=tab[i];           
   }else{
         tab2[i-10]=tab[i];
         }       
}

bubblesort(tab1,10);
bubblesort(tab2,10);


for (i=0 ; i<10 ; i++)
{

  printf("%d, ", tab1[i]);    
}
for (i=0 ; i<10 ; i++)
{

  printf("%d, ", tab2[i]);    
} 
  system("PAUSE"); 
  return 0;
}