等待一个项目到达受保护的对象

Waiting until an item arrives in a protected object

好的,Ada 任务分配对我来说很新而且很困惑。我有一个受保护对象的经典问题,该对象按 ID 作为键存储事件。这个想法是生产者任务用传入的事件填充它,一个或多个消费者任务需要等待 直到 给定 id 的事件到达,即它们应该阻塞直到它存储在地图,然后 return 那个事件。

目前的结构如下:

 package Reply_Storage is new Ada.Containers.Indefinite_Ordered_Maps
 (Key_Type     => Command_Id_Type,
  Element_Type => Event_Type);

 protected type Reply_Queue is
      procedure Put (Event : Event_Type);
      entry Take (Id : Command_Id_Type; Event : out Event_Type);
   private
      Storage : Reply_Storage.Map;
 end Reply_Queue;

 protected body Reply_Queue is
      procedure Put (Event : Event_Type) is
         Id : Command_Id_Type := Event_Command_Id (Event);
      begin
         Storage.Insert (Id, Event);
      end Put;
      entry Take (Id : Command_Id_Type; Event : out Event_Type) 
       when not Storage.Is_Empty is
      begin
         if Storage.Contains(Id) then
           Event := Storage.Element (Id);
            Storage.Delete (Id);
         end if;
      end Take;
 end Reply_Queue;

基本上,当 Storage.Is_Empty 时,我需要一个屏障 when Storage.Contains(Id)[=23=,而不是 ] 在条目正文中 Take。当然,这是不允许的,因为屏障的检查独立于入口调用。

但是如何实现想要的同步呢?

所以,你需要的是一个入口族(只适用于离散类型),像这样:

package Reply_Storage is new Ada.Containers.Indefinite_Ordered_Maps
 (Key_Type     => Command_Id_Type,
  Element_Type => Event_Type);

 protected type Reply_Queue is
      procedure Put (Event : Event_Type);
      entry Take (Command_Id_Type) (Event : out Event_Type); -- entry family
   private
      Storage : Reply_Storage.Map;
 end Reply_Queue;

 protected body Reply_Queue is
      procedure Put (Event : Event_Type) is
         Id : Command_Id_Type := Event_Command_Id (Event);
      begin
         Storage.Insert (Id, Event);
      end Put;
      entry Take (for Id in Command_Id_Type) (Event : out Event_Type) -- entry family
       when Storage.Contains(Id) is -- family designator (entry index) in barrier
      begin
         Event := Storage.Element (Id);
         Storage.Delete (Id);
      end Take;
 end Reply_Queue;