-
Notifications
You must be signed in to change notification settings - Fork 0
/
exercise7.adb
116 lines (99 loc) · 3.77 KB
/
exercise7.adb
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Numerics.Float_Random;
use Ada.Text_IO, Ada.Integer_Text_IO, Ada.Numerics.Float_Random;
procedure exercise7 is
Count_Failed : exception; -- Exception to be raised when counting fails
Gen : Generator; -- Random number generator
protected type Transaction_Manager (N : Positive) is
entry Finished;
function Commit return Boolean;
procedure Signal_Abort;
private
Finished_Gate_Open : Boolean := False;
Aborted : Boolean := False;
Should_Commit : Boolean := True;
end Transaction_Manager;
protected body Transaction_Manager is
entry Finished when Finished_Gate_Open or Finished'Count = N is
begin
------------------------------------------
-- PART 3: Complete the exit protocol here
------------------------------------------
Should_commit := not Aborted;
if Finished'Count > 0 then
Finished_Gate_Open := true;
else
Finished_Gate_Open := false;
end if;
if Finished'Count = 0 then
Aborted := false;
end if;
-------------------------------------------
end Finished;
procedure Signal_Abort is
begin
Aborted := True;
end Signal_Abort;
function Commit return Boolean is
begin
return Should_Commit;
end Commit;
end Transaction_Manager;
function Unreliable_Slow_Add (x : Integer) return Integer is
Error_Rate : Constant := 0.15; -- (between 0 and 1)
begin
-------------------------------------------
-- PART 1: Create the transaction work here
-------------------------------------------
if Random(Gen) < Error_Rate then
raise Count_Failed; -- raise = throw
else
delay 4*Duration(Random(Gen));
return x+10;
end if;
--------------------------------------------
end Unreliable_Slow_Add;
task type Transaction_Worker (Initial : Integer; Manager : access Transaction_Manager);
task body Transaction_Worker is
Num : Integer := Initial;
Prev : Integer := Num;
Round_Num : Integer := 0;
begin
Put_Line ("Worker" & Integer'Image(Initial) & " started");
loop
Put_Line ("Worker" & Integer'Image(Initial) & " started round" & Integer'Image(Round_Num));
Round_Num := Round_Num + 1;
---------------------------------------
-- PART 2: Do the transaction work here
---------------------------------------
begin
Prev := Num;
Num := Unreliable_Slow_Add(Num);
exception
when Count_Failed => Manager.Signal_Abort;
end;
Manager.Finished;
----------------------------------------
if Manager.Commit = True then
Put_Line (" Worker" & Integer'Image(Initial) & " comitting" & Integer'Image(Num));
else
Put_Line (" Worker" & Integer'Image(Initial) &
" reverting from" & Integer'Image(Num) &
" to" & Integer'Image(Prev));
-------------------------------------------
-- PART 2: Roll back to previous value here
-------------------------------------------
Num := Prev;
-------------------------------------------
end if;
Prev := Num;
delay 0.5;
end loop;
end Transaction_Worker;
Manager : aliased Transaction_Manager (3);
Worker_1 : Transaction_Worker (0, Manager'Access);
Worker_2 : Transaction_Worker (1, Manager'Access);
Worker_3 : Transaction_Worker (2, Manager'Access);
begin
Reset(Gen); -- Seed the
--number generator
end exercise7;