Rozpatrzmy teraz przydzielanie dwóch zasobów: A i B.
Przydzielanie zasobu A w sposób wyłączny i zasobu B w sposób wyłączny - prowadzi to do zagłodzenia procesów typu KlientAlubB, gdyż nigdy żaden zasób nie jest przydzielany tym procesom.
Przydzielanie zasoubu a w sposób przemienny i zasobu B w sposób wyłączny - żadna grupa procesów nie jest głodzona. Może się jednak zdażyć, że procesy z grupy KlientAlubB niepotrzebnie czekają. Dzieje się tak gdy nie można przydzielić zasobu A (bo już używa go X procesów), ale możnaby przydzielić zasób B (gdyż używa go mniej niż Y procesów). W tym algorytmie zasób B nie jest przydzielany procesom grupu KlientAlubB nawet gdy jest on dostępny. Nie prowadzi to jednak do ich zagłodzenia bo założyliśmy że (X>0) i zapewnienie postępu na zasobie a jest zagwarantowane dla tej grupy procesów - używamy algorytmu przemiennego.
Przydzielanie zasobu A w sposób przemienny i zasobu B w sposób przemienny - wtedy żadna grupa procesów nie jest głodzona. Nie zachodzi sytuacja taka (jak w porzednim podejściu), że proces nie korzysta z zasobów z których mógłby korzystać mimo że są dostępne.
type
PrzydzielenieTyp = (PrzydzielenieNull, PrzydzielonyA, PrzydzielonyAlubB, PrzydzielonyB);
Process Serwer;
var
dostepnych_a: integer := X;
dostepnych_b: integer := Y;
czeka_na_a: integer := 0;
czeka_na_b: integer := 0;
czeka_na_alubb: integer := 0;
ostatni_a_komu_przydzielony: PrzydzielenieTyp := PrzydzielenieNull;
ostatni_b_komu_przydzielony: PrzydzielenieTyp := PrzydzielenieNull;
op: OperacjaTyp;
Procedure sprawdz_a()
begin
if (dostepnych_a>0 and (czeka_na_a>0 or czeka_na_alubb>0)) then
begin
dostepnych_a := dostepncyh_a-1;
if (czeka_na_a=0 and czeka_na_alubb>0) then
begin
SendMsg(zasob_alubb, PozwolenieA);
czeka_na_alubb := czeka_na_alubb-1;
ostatni_a_komu_przydzielony := PrzydzielenieAlubB;
end;
else if (czeka_na_a>0 and czeka_na_alubb=0) then
begin
SendMsg(zasob_a, PozwolenieA);
czeka_na_a := czeka_na_a-1;
ostatni_a_komu_przydzielony := PrzydzielenieA;
end;
else {czeka_na_a>0 and czeka_na_alubb>0}
begin
case ostatni_a_komu_przydzielony of
PrzydzielenieNull:
SendMsg(zasob_a, PozwolenieA);
czeka_na_a := czeka_na_a-1;
ostatni_a_komu_przydzielony := PrzydzielenieA;
PrzydzielenieA:
SendMsg(zasob_alubb, PozwolenieA);
czeka_na_alubb := czeka_na_alubb-1;
ostatni_a_komu_przydzielony := PrzydzielenieAlubB;
PrzydzielenieAlubB:
SendMsg(zasob_a, PozwolenieA);
czeka_na_a := czeka_na_a-1;
ostatni_a_komu_przydzielony := PrzydzielenieA;
end; {case}
end;
end;
end;
Procedure sprawdz_b()
begin
...symetrycznie...
end;
begin
while (true) do
begin
op := GetMsg(operacja);
case op of
ChceA:
czeka_na_a := czeka_na_a+1;
ChceB:
czeka_na_b := czeka_na_b+1;
ChceAlubB:
czeka_na_alubb := czeka_na_alubb+1;
ZwalniamA:
dostepnych_a := dostepnych_a+1;
ZwalniamB:
dostepnych_b := dostepnych_b+1;
end; {case}
sprawdz_a();
sprawdz_b();
end;
end;
Rozwiązanie ma pewien mały mankament. Rozpatrzmy sytuację, gdy działają tylko procesy KlientAlubB, i załóżmy, że jest ich mniej niż X wtedy będą one korzystały tylko z zasoby A. Jest to priorytet dla zasobu A, w niektórych sytuacjach takie zachowanie może być nieoczekiwane. Rozwiązaniem tego problemu jest zapamiętywanie jaki zasób ostatnio został przydzielony procesowi z grupy KlientAlubB i w pierwszej kolejności przydzielanie innego zasobu następnemu procesowi z tej grupu. Osiągamy to pamiętając jaki zasób przydzieliliśmy ostatnio procesowi tej grupy i starając się najpierw przydzielić drugi zasób, a dopiero potem z ten sam zasób.
type
PrzydzielenieTyp = (PrzydzielenieNull, PrzydzielonyA, PrzydzielonyAlubB, PrzydzielonyB);
Process Serwer;
var
dostepnych_a: integer := X;
dostepnych_b: integer := Y;
czeka_na_a: integer := 0;
czeka_na_b: integer := 0;
czeka_na_alubb: integer := 0;
ostatni_a_komu_przydzielony: PrzydzielenieTyp := PrzydzielenieNull;
ostatni_b_komu_przydzielony: PrzydzielenieTyp := PrzydzielenieNull;
ostatni_alubb_przydzielony_przez: PrzydzielenieTyp := PrzydzielenieNull;
op: OperacjaTyp;
Procedure sprawdz_a()
begin
if (dostepnych_a>0 and (czeka_na_a>0 or czeka_na_alubb>0)) then
begin
dostepnych_a := dostepncyh_a-1;
if (czeka_na_a=0 and czeka_na_alubb>0) then
begin
SendMsg(zasob_alubb, PozwolenieA);
czeka_na_alubb := czeka_na_alubb-1;
ostatni_a_komu_przydzielony := PrzydzielenieAlubB;
end;
else if (czeka_na_a>0 and czeka_na_alubb=0) then
begin
SendMsg(zasob_a, PozwolenieA);
czeka_na_a := czeka_na_a-1;
ostatni_a_komu_przydzielony := PrzydzielenieA;
end;
else {czeka_na_a>0 and czeka_na_alubb>0}
begin
case ostatni_a_komu_przydzielony of
PrzydzielenieNull:
SendMsg(zasob_a, PozwolenieA);
czeka_na_a := czeka_na_a-1;
ostatni_a_komu_przydzielony := PrzydzielenieA;
PrzydzielenieA:
SendMsg(zasob_alubb, PozwolenieA);
czeka_na_alubb := czeka_na_alubb-1;
ostatni_a_komu_przydzielony := PrzydzielenieAlubB;
ostatni_alubb_przydzielony_przez := PrzydzielenieA;
PrzydzielenieAlubB:
SendMsg(zasob_a, PozwolenieA);
czeka_na_a := czeka_na_a-1;
ostatni_a_komu_przydzielony := PrzydzielenieA;
end; {case}
end;
end;
end;
Procedure sprawdz_b()
begin
...symetrycznie...
end;
begin
while (true) do
begin
op := GetMsg(operacja);
case op of
ChceA:
czeka_na_a := czeka_na_a+1;
ChceB:
czeka_na_b := czeka_na_b+1;
ChceAlubB:
czeka_na_alubb := czeka_na_alubb+1;
ZwalniamA:
dostepnych_a := dostepnych_a+1;
ZwalniamB:
dostepnych_b := dostepnych_b+1;
end; {case}
case (ostatni_alubb_przydzielony_przez) of
PrzydzielenieNull:
PrzydzielenieA:
sprawdz_b();
sprawdz_a();
PrzydzielenieB:
sprawdz_a();
sprawdz_b();
end; {case}
end;
end;