我正在尝试获取任务中的字段值。 Worker
循环相当庞大,所以我只留下重要的部分。基本上,当用户输入“w”时,我希望控制台打印有关这三个字段的信息。
奖金问题:任务组织Worker
有一个循环,我想在它的最后制作一个“FinishedJob ++”;但我也不知道怎么做。
任务不是记录。它不包含可以从任务外部直接访问的字段。您可以提供任务条目来查询在类中本地声明的变量的当前值,但请记住,条目强制在调用任务和被调用任务上进行同步。
你的“奖金问题”的措辞看起来像C或C ++思维。 Ada不仅仅是C或C ++,其开头和结尾替换为'{'和'}'。
您对FinishedJob计数有什么可见性?您似乎希望与另一个任务共享该号码,例如程序主任务。最简单的方法是创建一个受保护的对象,当工作任务完成时增加为外循环,并在适当时由读取任务读取。
这种受保护对象的一个可能的例子是:
protected Counter is
procedure Increment;
entry Read(Num : out Natural);
private
Tally : Natural := 0;
Is_Updated : Boolean := False;
end Counter;
protected body Counter is
procedure Increment is
begin
Tally := Tally + 1;
Is_Updated := True;
end Increment;
entry Read(Num : out Natural) when Is_Updated is
begin
Num := Tally;
Is_Updated := False;
end Read;
end Counter;
编写器在完成外部循环时调用Counter.Increment。读者调用Counter.Read并在可用时立即获取新值。
从您在屏幕截图中显示的内容来看,在我看来,您正在寻找一种方法来配置任务/工作者(Worker_Id
,Patient
(?))然后,在任务/工作人员启动后,一种监视方式它的进步(Jobs_Done
)。
假设如上所述,并且考虑到Jim Rogers已经做出的重要标记,知道通常通过所谓的任务判别式而不是初始accept
条目来配置任务可能是有趣的。任务判别式可以从任务外部访问(参见RM 9.1 (9)),并且根据定义是不可变的。因此,在您的情况下,您可以定义两个任务判别式,如
task type T_My_Task
(Worker_Id : Natural;
Patient : Boolean);
可以用作
declare
T1 : T_My_Task (1, True);
T2 : T_My_Task (2, True);
begin
Put_Line (T1.Worker_Id'Image);
Put_Line (T1.Patient'Image);
Put_Line (T2.Worker_Id'Image);
Put_Line (T2.Patient'Image);
end;
出于我自己的兴趣,我试图根据我认为你可以解决这个问题的方式制作一些示例程序。我很确定存在更多方法,我不会声称这是最好的方法。我提供了一些评论来澄清我(尝试)做的事情。它可能对你有用。
注意:我更新了以下关于我最初发布的示例,因为我对初始设计不满意。
main.adb(主程序)
with Ada.Text_IO; use Ada.Text_IO;
with Work_Force; use Work_Force;
procedure Main is
Worker_Configs : T_Worker_Config_Array :=
(0 => (Patient => True ),
1 => (Patient => False),
2 => (Patient => False),
3 => (Patient => True ),
4 => (Patient => False));
package My_Work_Force is
new Generic_Work_Force (Worker_Configs);
use My_Work_Force;
User_Response : Character;
begin
Main_Loop: loop
Put_Line ("--==[ MENU ]==--");
New_Line;
Put_Line (" S - Show status workers");
Put_Line (" Q - Quit");
New_Line;
Put (" ==> "); Get (User_Response);
New_Line;
case User_Response is
when 'S' =>
for Worker_Id in T_Worker_Id'Range loop
declare
Worker_Config : T_Worker_Config :=
Get_Worker_Config (Worker_Id);
Worker_Status : T_Worker_Status :=
Get_Worker_Status (Worker_Id);
begin
Put_Line (" Worker. . . : " & Worker_Id'Image);
Put_Line (" Patient . . : " & Worker_Config.Patient'Image);
Put_Line (" Jobs_Done . : " & Worker_Status.Jobs_Done'Image);
New_Line;
end;
end loop;
when 'Q' =>
-- The call "Terminate_All_Workers" is actually a request. The
-- call is non-blocking thanks to the protected object "Manager"
-- in the "Work_Force" package. The program itself, however,
-- will not terminate until all tasks have terminated (i.e.
-- exited the "Worker_Loop" (see task body of "T_Worker").
My_Work_Force.Terminate_All_Workers;
Put_Line ("Program will end when all workers have terminated.");
New_Line;
exit Main_Loop;
when others =>
Put_Line ("(Unknown option)");
New_Line;
end case;
end loop Main_Loop;
end Main;
work_force.ads(包规范;暂时无法提出更好的名称)
package Work_Force is
-- Record type "T_Worker_Config" contains all items required to configure
-- a worker. For now it contains only 1 item, but this can easily be
-- extended.
type T_Worker_Config is
record
Patient : Boolean;
end record;
type T_Worker_Config_Array is
array (Natural range <>) of aliased T_Worker_Config;
-- Record type "T_Worker_Status" contains all items related tot the status
-- of the worker. As for type "T_Worker_Config", it now contains only 1
-- item, but this can easily be extended.
type T_Worker_Status is
record
Jobs_Done : Natural;
end record;
generic
Workers_Config : T_Worker_Config_Array;
package Generic_Work_Force is
-- The package "Generic_Work_Force" exposes a restricted set of
-- subprograms such to have proper interface/implementation decoupling
-- (and reduce the impact of changes in the implementation, etc.).
subtype T_Worker_Id is
Natural range Workers_Config'Range;
function Get_Worker_Config
(Worker_Id : T_Worker_Id) return T_Worker_Config;
-- Gets the configuration from the worker "Worker_Id". A call to
-- this subprogram is non-blocking.
-- NOTE: "Get_Worker_Config" is not strictly necessary as the
-- "Workers_Config" parameter of the generic package can be accessed
-- directly from outside the package, but it looks nice and symmetric
-- with respect to the subprogram "Get_Worker_Status" below.
function Get_Worker_Status
(Worker_Id : T_Worker_Id) return T_Worker_Status;
-- Gets the status from the worker "Worker_Id". A call to this
-- subprogram is non-blocking.
procedure Terminate_All_Workers;
-- Request to terminate all workers. A call to this subprogram is
-- non-blocking.
-- NOTE: there is no private part in this spec as there are no
-- private types defined in the public part of the spec. All
-- implementation details can reside in the body such that they
-- can change independently from the spec, if necessary, without
-- the need to touch the spec file.
end Generic_Work_Force;
end Work_Force;
work_force.adb(包体)
package body Work_Force is
package body Generic_Work_Force is
-------------
-- Manager --
-------------
-- Protected object instance "Manager" is a synchronized
-- data object that administrates common requests to all workers.
protected Manager is
procedure Request_Termination;
-- Requests the termination of the workers.
-- ===> To be called from another task (e.g. the program main task).
function Is_Termination_Requested return Boolean;
-- Returns True if the termination is requested.
-- ===> To be called from a worker task.
private
Termination_Requested : Boolean := false;
end Manager;
protected body Manager is
procedure Request_Termination is
begin
Termination_Requested := True;
end Request_Termination;
function Is_Termination_Requested return Boolean is
begin
return Termination_Requested;
end Is_Termination_Requested;
end Manager;
-------------------
-- T_Worker_Data --
-------------------
-- Protected object type "T_Worker_Data" is a synchronized
-- data type that administrates dynamic worker data that must
-- be shared with other tasks.
protected type T_Worker_Data is
procedure Report_Job_Done;
-- Increments the "Jobs_Done" counter.
-- ===> To be called from a worker task.
function Get_Jobs_Done return Natural;
-- Returns the value of the "Jobs_Done" counter.
-- ===> To be called from another task (e.g. the program main task).
private
Jobs_Done : Natural := 0;
end T_Worker_Data;
protected body T_Worker_Data is
---------------------
-- Report_Job_Done --
---------------------
procedure Report_Job_Done is
begin
Jobs_Done := Jobs_Done + 1;
end Report_Job_Done;
-------------------
-- Get_Jobs_Done --
-------------------
function Get_Jobs_Done return Natural is
begin
return Jobs_Done;
end Get_Jobs_Done;
end T_Worker_Data;
--------------
-- T_Worker --
--------------
-- Task type "T_Worker" is the actual worker. Note that the worker
-- configuration, "Workers_Config (Worker_Id)", is visible to the
-- task as it is a parameter to the generic package.
task type T_Worker
(Worker_Id : T_Worker_Id;
Worker_Data : access T_Worker_Data);
task body T_Worker is
-- Just to show how to access the worker's configuration.
Patient : Boolean := Workers_Config (Worker_Id).Patient;
pragma Unreferenced (Patient);
begin
Worker_Loop: loop
if Manager.Is_Termination_Requested then
exit Worker_Loop;
end if;
-- Do some work...
delay (Worker_Id * 0.1 + 0.2);
-- Maybe check the termination request somewhere half-way (if
-- that's allowed, it might be that the worker must finish its job).
if Manager.Is_Termination_Requested then
exit Worker_Loop;
end if;
-- Continue the work...
delay (Worker_Id * 0.1 + 0.2);
-- Report job done.
Worker_Data.Report_Job_Done;
end loop Worker_Loop;
end T_Worker;
-- Arrays that will hold the instances of "T_Worker" and "T_Worker_Data".
-- The initialization will be done in the package initialization section
-- which is executed during the elaboration of the package.
Workers : array (T_Worker_Id'Range) of access T_Worker;
Workers_Data : array (T_Worker_Id'Range) of access T_Worker_Data;
-----------------------
-- Get_Worker_Config --
-----------------------
function Get_Worker_Config
(Worker_Id : T_Worker_Id) return T_Worker_Config
is
begin
return Workers_Config (Worker_Id);
end Get_Worker_Config;
-----------------------
-- Get_Worker_Status --
-----------------------
function Get_Worker_Status
(Worker_Id : T_Worker_Id) return T_Worker_Status
is
begin
return (Jobs_Done => Workers_Data (Worker_Id).Get_Jobs_Done);
end Get_Worker_Status;
---------------------------
-- Terminate_All_Workers --
---------------------------
procedure Terminate_All_Workers is
begin
Manager.Request_Termination;
end Terminate_All_Workers;
-- Start processing for Generic_Work_Force.
begin
-- This is the initialization sequence of the package which will be
-- called during its elaboration.
for Worker_Id in T_Worker_Id'Range loop
Workers_Data (Worker_Id) :=
new T_Worker_Data;
Workers (Worker_Id) :=
new T_Worker
(Worker_Id => Worker_Id,
Worker_Data => Workers_Data (Worker_Id));
end loop;
end Generic_Work_Force;
end Work_Force;