Rozwiązanie

Rozpatrzmy teraz przydzielanie dwóch zasobów: A i 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;
 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;