poniedziałek, 26 grudnia 2011

[Ada | EN] Circular buffer using protected object

Theme
How to implement circular buffer in Ada programming language with use of protected object.

Circular buffer is a simple data structure that contains an fixed size array and two data pointers (start of valid data and the end of valid data). Protected object provides mutual exclusion of two synchronous tasks (Producer and Consumer). Data inside buffer is being modified by calling (with random delay times) one of two entries (Add, Take). Each of them contains a when statement that ensures data cohesion. If one of entries is being called and a condition associated with apropriate when statement is not fullfilled, the task is being suspended until the condition is done.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
with Ada.Text_Io;
use Ada.Text_Io;
with Ada.Numerics.Discrete_Random;
 
 
procedure Cyclic_Buffer is
 
   type Buffer is array (Integer range <>) of Integer;
   Size : Integer:=5;
 
   subtype Wait is Integer range 0..5;
   package Draw is new Ada.Numerics.Discrete_Random(Wait);
   use Draw;
   G : Generator;
 
   protected Protected_Buffer is
      entry Add(I : in Integer);
      entry Take(I : out Integer);
   private 
      B : Buffer(1..Size);   
      Counter : Integer:=0;
      GetIndex : Integer:=1;
      PutIndex : Integer:=1;
         
 end Protected_Buffer;
   
   task Producer;
   task Consumer;
 
   protected body Protected_Buffer is
 
      entry Add(I : in Integer) when Counter < Size is
      begin
         B(PutIndex) := I;
         PutIndex := PutIndex mod Size + 1;
         Counter := Counter + 1;                   
         end Add;
 
      entry Take(I : out Integer) when Counter > 0 is
      begin
         I:=B(GetIndex);
         GetIndex := GetIndex mod Size + 1;  
         Counter := Counter - 1;      
         end Take;
   end Protected_Buffer;   
   
 
 
task body Consumer is
   Cons_Delay_Time : Integer;
begin
   loop
      Reset(G);
      Cons_Delay_Time:=Integer(Random(G));
      delay Duration(1.3*Float(Cons_Delay_Time));
      Protected_Buffer.Take(Cons_Delay_Time);
      Put_Line("Consumer : Taking "&Cons_Delay_Time'Img);
      delay 0.15;
    end loop;
end Consumer;
 
task body Producer is
   Prod_Delay_Time : Integer;
begin
   loop
      Reset(G);
      Prod_Delay_Time := Integer(Random(G));
      delay Duration(Prod_Delay_Time);
      Protected_Buffer.Add(Prod_Delay_Time);
      Put_Line("Producer : Adding "&Prod_Delay_Time'Img);
      delay 0.15;
   end loop;
end Producer;
 
begin
   null;
end Cyclic_Buffer;

Comments:
[11 - 14] Random number generator declaration. It draws consecutive delay times for both tasks.
[27 - 28] Tasks are being triggered
[55] Delay time depends on a drawn number
[56] Local variable associates now with a value from the buffer
[77] All the instructions are being evolved in tasks so null instruction is here sufficient

Compiler: Ideone.com

niedziela, 25 grudnia 2011

[Ada | PL] Bufor cykliczny na obiekcie chronionym

Temat:
Realizacja bufora cyklicznego w języku Ada z wykorzystaniem obiektu chronionego.

Bufor cykliczny to prosta struktura danych zrealizowana w przypadku tego programu na tablicy pięcioelementowej, gdzie dane dodawane są i pobierane zgodnie z indeksami wskaźników (w programie GetIndex i PutIndex). Obiekt chroniony zapewnia wzajemne wykluczanie dostępu do zasobów dwóch współbieżnie działających zadań (producenta i konsumenta). Modyfikowanie danych w tablicy dokonuje się za pomocą dwóch instrukcji entry wywoływanych z obu zadań w losowych chwilach czasu. Instrukcje te zapewniają nie tylko synchronizację zadań, ale także zawieszenie zadania, jeśli nie jest spełniony warunek zapisany instrukcją when. Zadanie zostaje odwieszone, gdy warunek ponownie zostanie spełniony.



1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
with Ada.Text_Io;
use Ada.Text_Io;
with Ada.Numerics.Discrete_Random;
 
 
procedure Cyclic_Buffer is
 
   type Buffer is array (Integer range <>) of Integer;
   Size : Integer:=5;
 
   subtype Wait is Integer range 0..5;
   package Draw is new Ada.Numerics.Discrete_Random(Wait);
   use Draw;
   G : Generator;
 
   protected Protected_Buffer is
      entry Add(I : in Integer);
      entry Take(I : out Integer);
   private 
      B : Buffer(1..Size);   
      Counter : Integer:=0;
      GetIndex : Integer:=1;
      PutIndex : Integer:=1;
         
 end Protected_Buffer;
   
   task Producer;
   task Consumer;
 
   protected body Protected_Buffer is
 
      entry Add(I : in Integer) when Counter < Size is
      begin
         B(PutIndex) := I;
         PutIndex := PutIndex mod Size + 1;
         Counter := Counter + 1;                   
         end Add;
 
      entry Take(I : out Integer) when Counter > 0 is
      begin
         I:=B(GetIndex);
         GetIndex := GetIndex mod Size + 1;  
         Counter := Counter - 1;      
         end Take;
   end Protected_Buffer;   
   
 
 
task body Consumer is
   Cons_Delay_Time : Integer;
begin
   loop
      Reset(G);
      Cons_Delay_Time:=Integer(Random(G));
      delay Duration(1.3*Float(Cons_Delay_Time));
      Protected_Buffer.Take(Cons_Delay_Time);
      Put_Line("Consumer : Taking "&Cons_Delay_Time'Img);
      delay 0.15;
    end loop;
end Consumer;
 
task body Producer is
   Prod_Delay_Time : Integer;
begin
   loop
      Reset(G);
      Prod_Delay_Time := Integer(Random(G));
      delay Duration(Prod_Delay_Time);
      Protected_Buffer.Add(Prod_Delay_Time);
      Put_Line("Producer : Adding "&Prod_Delay_Time'Img);
      delay 0.15;
   end loop;
end Producer;
 
begin
   null;
end Cyclic_Buffer;

Komentarze:
[11 - 14] Deklaracje generatora liczb pseudolosowych, który odpowiada za losowe czasy opóźnienia w działaniu obu zadań (od 0 do 5 sek).
[27 - 28] Uruchomienie wykonywania zadań
[55] Opóźnienie wykonywania zadania zależne od wylosowanej liczby
[56] Pobranie z bufora wartości do zmiennej lokalnej
[77] Pusta instrukcja programu - wszystkie instrukcje wykonują się w dwóch współbieżnych zadaniach

Kompilator: Ideone.com