-
Notifications
You must be signed in to change notification settings - Fork 0
/
exercise7.adb~
128 lines (97 loc) · 3.89 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
116
117
118
119
120
121
122
123
124
125
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
if Finished'Count = N-1 then
Should_Commit := not Aborted;
Finished_Gate_Open := True;
end if;
if Finished'Count = 0 then
Should_Commit := not Aborted;
Finished_Gate_Open := False;
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)
x_new : Integer := 0
begin
-------------------------------------------
-- PART 1: Create the transaction work here
if Random(Gen) > Error_Rate then
delay Duration(4.0);
x_new := 10+x;
return x_new;
else
delay Duration(0.5);
raise Count_Failed;
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
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 random number generator
end exercise7;