4.
Sincronizarea proceselor
4.1. Problema cititorilor şi scriitorilor
Un obiect (care poate fi o resursă, de exemplu un fişier sau o zonă de memorie) este
partajat de mai multe procese concurente. Dintre aceste procese, unele doar vor citi conţinutul
obiectului partajat şi aceste procese poartă numele de cititori, iar celelalte vor scrie în conţinutul
obiectului partajat, purtând numele de scriitori.
Cerinţa este ca scriitorii să aibă acces exclusiv la obiectul partajat, în timp ce cititorii să
poată accesa obiectul în mod concurent (neexclusiv).
Există mai multe posibilităţi de a soluţiona această problemă. Vom aminti două variante:
Varianta 1
Nici un cititor nu va fi ţinut în aşteptare, decât dacă un scriitor a obţinut deja
permisiunea de acces la obiectul partajat.
La un acces simultan la obiectul partajat atât al scriitorilor, cât şi al cititorilor, cititorii au
prioritate.
Varianta 2
Când un scriitor este gata de scriere, el va executa scrierea cât mai curând posibil. La un
acces simultan, scriitorii sânt prioritari.
Oricum, în ambele cazuri, problema principală ce trebuie rezolvată este înfometarea,
adică aşteptarea la infinit a obţinerii dreptului de acces.
Implementăm un program pentru prima variantă, folosind următoarele semafoare,
mutexuri şi variabile:
scrie – un semafor cu mai multe roluri; el asigură excluderea
mutuală a scriitorilor; este folosit de către primul cititor care intră în propria secţiune critică; de remarcat
că acest semafor nu este utilizat de cititorii care intră sau ies din secţiunea critică în timp ce alţi cititori se
află în propria secţiune critică;
contorcitire – o variabilă care are rolul de a ţine evidenţa
numărului de procese existente în cursul citirii;
semcontor – un semafor care asigură excluderea mutuală când
este actualizată variabila contorcitire.
Dacă un scriitor este în secţiunea critică şi n cititori aşteaptă, atunci un cititor aşteaptă la
semaforul scriere, iar ceilalţi nu-1 aşteaptă la semcontor.
La signal(scrie) se poate relua fie execuţia unui singur scriitor, fie a cititorilor aflaţi în
aşteptare, decizia fiind luată de planificator.
În continuare dăm programul algoritm pentru prima variantă:
Exemplul 1: nici un cititor nu va fi ţinut în aşteptare, decât
dacă un scriitor a obţinut deja permisiunea de acces la obiectul
partajat.
int semafor; /*declaraţii şi iniţializări*/
int contorcitire=0;
semafor scrie=1,
semcontor=1 ;
void scriitor()
{wait(scrie) ;
scriereobiect() ;
signal(scrie) ;}
void cititor()
{wait(semcontor) ;
contor citire++;
if(contorcitire==1)wait(scrie);
//primul cititor
signal(semcontor);
citireobiect();
wait(semcontor);
contor citire--;
if(contorcitire==0)signal(scrie);
//ultimul cititor
signal(semcontor);}
Considerăm o bază de date şi multe procese prin care se poate accesa această bază de
date pentru scriere sau citire. Se permite ca mai multe procese să citească simultan, dar dacă unul
din procese vrea să scrie (să modifice) baza de date, nici unul din celelalte procese nu are voie să
acceseze baza de date (nici pentru scriere, nici pentru citire).
Mai jos, prezentăm o soluţie.
Primul cititor care accesează baza de date execută un DOWN pe un semafor db
(nepermiţand nici unui scriitor să acceseze baza de date). Următorii cititori incrementează un
contor rc. Pe măsură ce cititorii pleacă, contorul este decrementat, iar ultimul execută un UP pe
semaforul db, permiţand astfel scriitorului blocat, dacă există, să acceseze baza de date.
Această soluţie dă prioritate cititorilor asupra scriitorilor. Astfel, dacă un scriitor apare în
timp ce alţi cititori se află deja în baza de date, scriitorul trebuie să astepte până pleacă toţi
cititorii.
Exemplul 2: prioritatea cititorilor asupra scriitorilor.
int semafor; /*Controlează accesul
semafor mutex=1; la rc controlează accesul
semafor db=1; la baza de date */
int rc=0; /* nr. procese cititor */
void
cititor(void){
while(1){ /* ciclu infinit */
/* acces exclusiv al
down(mutex); variabilei rc */
if(+ /*dacă este primul
+rc==1) cititor => nici un alt
scriitor nu mai*/
down(db); /*poate accesa baza de date*/
/*iese din regiunea critică*/
up(mutex);
/*accesează baza de date */
citeste_baza_de_
date();
/* acces exclusiv al
down(mutex); variabilei rc */
if(--
rc==0) /* dacă este ultimul
cititor => se permite
up(db); accesul scriitorilor */
up(mutex); /*iese din regiunea critică*/
}
}
void scriitor(){
while(1){ /* ciclu infinit */
down(db); /* acces exclusiv la baza
de date */
/* modifică baza de date */
scrie_în_baza_de
_date();
up(db); /* permite altor procese
să acceseze baza de date*/
}}
Soluţionarea problemii clasice a cititorilor şi scriitorilor pentru mai mulţi cititori şi mai
mulţi scriitori. Scriitorii şi cititorii lucrează cu mai multe obiecte.
Exemplul 3: realizarea problemei cititorilor şi scriitorilor
import [Link].*;
public class Lab2Sola {
int NrWritters=16;
int NrReaders=30;
int NrBooks=9;
int[] stare=new int[NrWritters];
class Writer extends Thread {
private Library lyb;
private int number;
private int writenBooks;
public Writer(Library c, int number) {
lyb = c;
[Link] = number;
[Link]=0;
}
public @Override void run() {
Random r=new Random();
int value=0;
int index=0;
while([Link]<NrBooks) {
if([Link]){
[Link]=false;
[Link]("Scriitorul "+number+" asteapta...");
while(true){
if([Link]<=0){
[Link]("Scriitorul "+number+
" a intrat in biblioteca.");
value=[Link](100);
index=[Link]([Link]);
[Link](value,index);
[Link]++;
[Link]=0;
break;
}
else{
try{
sleep(50);
}catch(InterruptedException e) { }
}}
[Link]=true;
[Link]("Scriitorul "+number+" scrie: "+value+" a
"+[Link]+" carte in indexul: "+index);
//notify();//All();
try{
sleep(300);
}catch(InterruptedException e) { }
}
else{
try{
sleep(200);
}catch(InterruptedException e) { }
}}
if([Link]>=NrBooks) {
stare[[Link]]=1;
}}}
class Reader extends Thread {
private Library lyb;
private int number;
public Reader(Library c, int number) {
lyb = c;
[Link] = number;
}
public @Override void run() {
Random r=new Random();
int value;
int index;
while(verify()!=1){
if([Link]){
[Link]++;
[Link]("Cititorul "+number+"
a intrat in biblioteca.");
index=[Link]([Link]);
value = [Link](index);
try{
sleep(1);
}catch(InterruptedException e) { }
[Link]("Cititorul "+number+" a citit: "+value+" la
indexul: "+index); [Link]("Cititorul
"+number+" a iesit din biblioteca.");
[Link]--;
//notify();
try{
sleep(100);
}catch(InterruptedException e) { }
}
else{
try{
sleep(200);
}catch(InterruptedException e) { }
}}}}
static class Library {
public boolean accessAllowed;
public int readersCount;
public int info[];
public int capacity;
public Library(){
accessAllowed=true;
readersCount=0;
capacity=30;
info=new int[30];
for(int i=0;i<capacity;i++){
info[i]=i;
}}
public int read(int i) {
return info[i];
}
public void write(int newInfo,int i) {
info[i]=newInfo;
}}
private int verify(){
for (int i=0;i<NrWritters;i++){
if ([Link][i]==0)
return 0;
} return 1;
}
public void run(){
for( int i=0;i<16;i++){
Library lib=new Library();
Writer scriitor=new Writer(lib, i);
[Link]();
}
for(int j=0;j<30;j++){
Library lib=new Library();
Reader cititor=new Reader(lib,j);
[Link]();
}
while(true){
if([Link]()==1)
// [Link](0);
{
[Link]("Scriitorii au terminat de scris");
[Link](0);
}}}
public static void main(String[] args) {
new Lab2Sola().run();
}}
4.2. Lucrarea de laborator nr. 4
1. Tema lucrării:
Implimentarea metodelor de sincronizare a proceselor
2. Scopul lucrării:
Însuşirea modalităţilor şi a mecanizmelor de sincronizare;
Însuşirea modalităţilor de realizare a mecanizmelor de sincronizare;
3. Etapele de efectuare:
sincronizarea firelor de execuţie;
realizarea metodelor de sincronizare a firelor de execuţie;
crearea interfeţii programului;
prezentarea lucrării.
4. Exemplu de efectuare:
package sola5_nb;
import [Link].*;
class Writer extends Thread{
private static int writtenbooks=0;
private String name;
public static int semaphore=0;
public static Vector<String> writtenCount=new
Vector<String>();
// public static int writerCount=9;
public static int bookCount=14;
public Writer(int name){
[Link]=[Link](name);
[Link](name + " Scriitor ");
}
public void run(){
while(writtenbooks<bookCount){
if (semaphore==0){
semaphore=1;
writtenbooks++;
[Link]([Link]
(writtenbooks));
[Link](" Obiectul este scris " + writtenbooks + "
de scriitorul " + name);
[Link](" Obiecte scrise " + [Link]());
if ([Link]()==bookCount){
[Link]("\n---Toate obiectele sânt scrise---\n");
}
semaphore=0;
try
{sleep(1000);}
catch(InterruptedException e){
}}}
[Link]();
}}
class Reader extends Thread{
private static int readbooks=0;
private static int stopAll=0;
private String name;
public static Vector<String> readCount=new Vector<String>();
public Reader(int name){
[Link]=[Link](name);
[Link](" "+name + " Cititor");
}
public void run(){
if ([Link]==0)
while (readbooks<[Link]){
for(int i=0; i<[Link](); i++){
if ([Link]()==readbooks){
if (stopAll==0){
[Link](" Obiecte necitite " +
([Link]-readbooks));
[Link]("----Toate obiectele scrise sânt
citite-----");
stopAll=1;
}
[Link]();
}
else{
[Link](" Este citit obiectul " +
[Link](i) + " de cititorul " + name);
if ([Link](i).equals("0")){
[Link](i, "1");
readbooks++;
}
try
{ sleep(500);}
catch(InterruptedException e){
}}}}
[Link]();
}}
public class lab_sola{
public static void main(String[] args){
[Link]=new Vector<String>();
//vectorul pentru obiectele citite
for (int i=0; i<14; i++)
[Link]([Link](0));
//iniţializarea tabloului cu 0
Vector<Writer> w=new Vector<Writer>();
//cititorii
for(int i=0; i<9; i++){
/*fiecare scriitor adaugă în poziţia "i" cu numele, identic cu
numărul poziţiei*/
[Link](i, new Writer(i+1));
}
Vector<Reader> r=new Vector<Reader>()
//cititorii
for(int i=0; i<2; i++){
[Link](i, new Reader(i+1));
}
/*ciclu pentru firele de execuţie, egal
max(numărul de scriitori, numărul de cititori)*/
for(int i=0; i<[Link]([Link](), [Link]()); i++)
{
/*dacă elementul curent este între scriitori/citirori, îl
activăm */
if (i<[Link]()) [Link](i).start();
if (i<[Link]()) [Link](i).start();
}}}
Rezultatul realizării programului:
run:
1 Scriitor
2 Scriitor
3 Scriitor
4 Scriitor
5 Scriitor
6 Scriitor
7 Scriitor
8 Scriitor
9 Scriitor
1 Cititor
2 Cititor
E scris obiectul 1 de scriitorul 1
Obiecte scrise 1
E scris obiectul 2 de scriitorul 2
Obiecte scrise 2
E scris obiectul 3 de scriitorul 3
Obiecte scrise 3
A fost citit obiectul 1 de cititorul 2
E scris obiectul 4 de scriitorul 5
Obiecte scrise 4
E scris obiectul 5 de scriitorul 4
Obiecte scrise 5
E scris obiectul 6 de scriitorul 9
Obiecte scrise 6
E scris obiectul 7 de scriitorul 6
Obiecte scrise 7
E scris obiectul 8 de scriitorul 8
Obiecte scrise 8
A fost citit obiectul 1 de cititorul 1
E scris obiectul 9 de scriitorul 7
Obiecte scrise 9
A fost citit obiectul 2 de cititorul 2
A fost citit obiectul 2 de cititorul 1
E scris obiectul 10 de scriitorul 2
Obiecte scrise 10
A fost citit obiectul 3 de cititorul 2
E scris obiectul 11 de scriitorul 5
Obiecte scrise 11
E scris obiectul 12 de scriitorul 1
Obiecte scrise 12
E scris obiectul 13 de scriitorul 3
Obiecte scrise 13
E scris obiectul 14 de scriitorul 6
A fost citit obiectul 3 de cititorul 1
Obiecte scrise 14
-----Obiectele toate sânt scrise-----
A fost citit obiectul 4 de cititorul 2
A fost citit obiectul 4 de cititorul 1
A fost citit obiectul 5 de cititorul 2
A fost citit obiectul 5 de cititorul 1
A fost citit obiectul 6 de cititorul 2
A fost citit obiectul 6 de cititorul 1
A fost citit obiectul 7 de cititorul 2
A fost citit obiectul 7 de cititorul 1
A fost citit obiectul 8 de cititorul 2
A fost citit obiectul 8 de cititorul 1
A fost citit obiectul 9 de cititorul 2
A fost citit obiectul 9 de cititorul 1
A fost citit obiectul 10 de cititorul 2
A fost citit obiectul 10 de cititorul 1
A fost citit obiectul 11 de cititorul 2
A fost citit obiectul 11 de cititorul 1
A fost citit obiectul 12 de cititorul 2
A fost citit obiectul 12 de cititorul 1
A fost citit obiectul 13 de cititorul 2
A fost citit obiectul 13 de cititorul 1
A fost citit obiectul 14 de cititorul 2
Obiecte necitite 0
-----Toate obiectele scrise au fost citite-----
BUILD SUCCESSFUL (total time: 7 seconds)
5. Probleme propuse:
Scrieţi un program pentru X (unde X este egal cu numărul variantei plus numărul
subgrupei) scriitori şi Y (unde Y este egal cu numărul variantei înmulţit cu 2 plus numărul
subgrupei) cititori, fiecare scriitor scrie cîte Z (unde Z este egal cu numărul variantei plus 3)
obiecte.