练习一 Scope
任何task都要在他的子任务结束后才能结束。
对于以下的程序 请给出输出顺序
with Ada.Calendar; use Ada.Calendar;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
procedure Task_Scopes is
Start_Up_Time : constant Time := Clock;
procedure Put_Line_Time (S : String) is
begin
-- Prefixes the time since startup as seconds with two decimal places
Put (Float (Clock - Start_Up_Time), 1, 2, 0); Put_Line (" seconds: " & S);
end Put_Line_Time;
task type Outer_Type;
type Outer_Type_Ptr is access Outer_Type;
task body Outer_Type is
begin
delay 0.6; Put_Line_Time ("-- End of an outer task");
end Outer_Type;
task Static_Outer_Task;
task body Static_Outer_Task is
begin
delay 0.1; Put_Line_Time ("Start of Static_Outer_Task");
declare
task type Inner_Type;
type Inner_Type_Ptr is access Inner_Type;
task body Inner_Type is
begin
delay 0.6; Put_Line_Time ("-- End of an inner task");
end Inner_Type;
task Static_Inner_Task;
task body Static_Inner_Task is
begin
delay 0.2; Put_Line_Time ("Start of Static_Inner_Task");
declare
Inner_Task_Instance : Inner_Type;
Outer_Task_Instance : Outer_Type;
Dynamic_Inner_Instance : Inner_Type_Ptr := new Inner_Type;
-- Dynamic_Outer_Instance : Outer_Type_Ptr := new Outer_Type;
begin
delay 0.3; Put_Line_Time ("End of Static_Inner_Task declare block");
end;
delay 0.1; Put_Line_Time ("End of Static_Inner_Task");
end Static_Inner_Task;
begin
delay 0.4; Put_Line_Time ("End of Static_Outer_Task declare block");
end;
delay 0.1; Put_Line_Time ("End of Static_Outer_Task");
end Static_Outer_Task;
begin
delay 0.2; Put_Line_Time ("Start of main scope");
delay 0.2; Put_Line_Time ("End of main scope");
end Task_Scopes;
运行结果:
分析:Ada中有两个种类的task
- static
这一类都是直接在声明然后使用。他的存活范围为生成task时所在的范围(scope)。 - dynamic
这一类就使用access关键字来表示(指针):
声明:
type Outer_Type_Ptr is access Outer_Type;
实例化:
Dynamic_Outer_Instance : Outer_Type_Ptr := new Outer_Type;
这一类的存活范围为其原task声明所在的范围,即与其在哪里被生成无关。
之所以用到了指针而不用重新声明一个新的task,主要是考虑到了存储空间的问题。
最后,散乱分布的相同的dynamic task会被同一个task 回收,这是最有利的一点。
练习二 Concurrent Mergesort
实现一个concurrent mergesort。
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Text_IO; use Ada.Text_IO;
with CPU_Counter; use CPU_Counter;
procedure Concurrent_Mergesort (Sort_Field : in out Element_Array) is
procedure Mergesort (F : in out Element_Array) is
begin
if F'Length > 1 then
declare
Middle : constant Index := Index'Val (Index'Pos (F'First) + F'Length / 2);
subtype Low_Range is Index range F'First .. Index'Pred (Middle);
subtype High_Range is Index range Middle .. F'Last;
F_Low : aliased Element_Array := F (Low_Range);
F_High : aliased Element_Array := F (High_Range);
Gained_Agent : Boolean := False;
begin
if CPUs_Potentially_Available then
CPU_Count.Try_Check_One_Out (Gained_Agent);
end if;
if Gained_Agent then ## 关键部分
declare
task sort_L;
task body sort_L is
begin
Mergesort (F_Low);
end;
task sort_H;
task body sort_H is
begin
Mergesort (F_High);
end;
begin
null;
end; ##关键部分
else
Mergesort (F_Low);
Mergesort (F_High);
end if;
declare
Low : Low_Range := Low_Range'First;
High : High_Range := High_Range'First;
Low_Element : Element := F_Low (Low);
High_Element : Element := F_High (High);
begin
Merge : for i in F'Range loop
if Low_Element < High_Element then
F (i) := Low_Element;
if Low = F_Low'Last then
F (Index'Succ (i) .. F'Last) := F_High (High .. F_High'Last);
exit Merge;
else
Low := Index'Succ (Low); Low_Element := F_Low (Low);
end if;
else
F (i) := High_Element;
if High = F_High'Last then
F (Index'Succ (i) .. F'Last) := F_Low (Low .. F_Low'Last);
exit Merge;
else
High := Index'Succ (High); High_Element := F_High (High);
end if;
end if;
end loop Merge;
end;
end;
end if;
end Mergesort;
begin
Mergesort (Sort_Field);
end Concurrent_Mergesort;
在以上关键部分,我用了两个并行的task 代替了原来顺序执行的 Mergesort (F_Low), Mergesort (F_High);
因为mergesort的关键就是separation,其中的顺序执行就在于其中一组已经排列好了,而等待下一组的排列。所以我们做的就是让他们同时进行。
效果: