获取任务中的字段值

问题描述 投票:1回答:2

我正在尝试获取任务中的字段值。 Worker循环相当庞大,所以我只留下重要的部分。基本上,当用户输入“w”时,我希望控制台打印有关这三个字段的信息。

image

奖金问题:任务组织Worker有一个循环,我想在它的最后制作一个“FinishedJob ++”;但我也不知道怎么做。

ada
2个回答
3
投票

任务不是记录。它不包含可以从任务外部直接访问的字段。您可以提供任务条目来查询在类中本地声明的变量的当前值,但请记住,条目强制在调用任务和被调用任务上进行同步。

你的“奖金问题”的措辞看起来像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并在可用时立即获取新值。


2
投票

从您在屏幕截图中显示的内容来看,在我看来,您正在寻找一种方法来配置任务/工作者(Worker_IdPatient(?))然后,在任务/工作人员启动后,一种监视方式它的进步(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;
© www.soinside.com 2019 - 2024. All rights reserved.