Как запустить однозадачное задание в пакете ada - PullRequest
4 голосов
/ 09 февраля 2020

Я делаю немного Ады в это воскресенье ..; -)

Я написал небольшой пакет журнала:

log.ads:

package Log is
    procedure log (text: String);
end Log;

log. adb:

with Ada.Text_IO;

package body Log is

    procedure log (text: String) is
    begin
        Ada.Text_IO.Put (text);
    end log;

end Log;

Я могу использовать это так: test.adb:

with Log;

procedure Test is
begin
    Log.log ("bla bla");
end Test;

Теперь я хотел бы "улучшить" этот пакет. Я хотел бы, чтобы процедура журнала "pu sh" текст к задаче. Это задача, которая выполняет «Ada.Text_IO.Put (text)». Задача может быть:

task Logger_Task is
    entry log (text : String);
end Logger_Task;

task body Logger_Task is
begin
    loop
        accept log (text: String) do
            Ada.Text_IO.Put (text);
        end log;
    end loop;
end Logger_Task;

Мне бы хотелось, чтобы клиенты Log не знали об этой задаче, поэтому она должна быть где-то скрыта в пакете Log. Я не знаю, как и где создать экземпляр задачи ...

Эта задача также должна оставаться активной в течение всего срока действия приложения.

Спасибо за вашу помощь.

Ответы [ 3 ]

5 голосов
/ 10 февраля 2020

Если вы определяете задачу в теле пакета, вы можете сохранить интерфейс procedure log:

with Ada.Text_IO.Unbounded_IO;
with Ada.Strings.Unbounded;

package body Log is

   task Logger_Task is
      entry log (text : String);
   end Logger_Task;

   task body Logger_Task is
      Cache: Ada.Strings.Unbounded.Unbounded_String;
   begin
      loop
         select
            accept log (text: String) do
               Cache := Ada.Strings.Unbounded.To_Unbounded_String (text);
            end log;
            Ada.Text_IO.Unbounded_IO.Put (Cache);
         or
            terminate;
         end select;
      end loop;
   end Logger_Task;

   procedure log (text: String) is
   begin
      Logger_Task.log (text);
   end log;
end Log;

select … or terminate; жизненно важно для завершения задачи, когда основная задача заканчивается (эта альтернатива будет выполняться только тогда, когда основная задача достигла своего конца).

Cache также важна, поскольку позволяет продолжить выполнение вызывающей задачи после получения параметра text блоком accept. Непосредственный вызов Put в блоке accept заставит вызывающую задачу ждать, пока она не завершится sh, поскольку она продолжается только после того, как блок accept был оставлен.

5 голосов
/ 09 февраля 2020

Вы уже создали его экземпляр.

task Logger_Task is
    entry log (text : String);
end Logger_Task;

- это то же самое, что создание экземпляра анонимного task type:

task type Anonymous is
    entry log (text : String);
end Anonymous;
Logger_Task : Anonymous;
1 голос
/ 12 февраля 2020

Метод, использующий рандеву, был показан другим пользователем, но если средства обработки этого сообщения могут блокироваться, то даже если вы сделаете это вне оператора accept, вызывающая сторона может потенциально заблокировать ожидание задачи регистратора, чтобы вернуться назад. принять заявление. Text_IO не должен быть большой проблемой, но для других типов выходов, которые потенциально могут блокировать дольше, рассмотрите альтернативу:

Используйте неограниченную синхронизированную очередь в сочетании с автономной задачей, которая контролирует очереди и извлекает из него сообщения по мере их добавления, и у него есть время. Даже если это запись, операция Enqueue не будет блокировать вызывающую задачу. Таким образом, если метод вывода для вашего регистратора иногда блокируется на относительно длительные периоды времени, другие ваши задачи будут просто выводить сообщения в очередь и двигаться дальше, и задача мониторинга в конечном итоге будет выводить их, когда догонит.

logging.ads

package Logging is

   procedure Put_Line(Message : String);

end Logging;

logging.adb

with Ada.Containers.Synchronized_Queue_Interfaces;
with Ada.Containers.Unbounded_Synchronized_Queues;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
use Ada.Containers;
with Ada.Task_Identification; use Ada.Task_Identification;
with Ada.Text_IO;
with Ada.Text_IO.Unbounded_IO;

package body Logging is

   -- Create the queue
   package Interfaces is new Synchronized_Queue_Interfaces(Unbounded_String);
   package Queues is new Unbounded_Synchronized_Queues(Interfaces);
   Messages : Queues.Queue;

   -- This task will monitor the queue until the program ends
   task Logger;

   task body Logger is
      Message : Unbounded_String := Null_Unbounded_String;
   begin

      -- Stop looping once both main ends and there are no messages left
      -- The Environment_Task refers to the task that runs Main
      while Is_Callable(Environment_Task) or Messages.Current_Use > 0 loop

         -- Check the queue for a message but time out if not.  We
         -- need the timeout because Dequeue can block if the queue 
         -- is empty.
         select
            Messages.Dequeue(Message);
            Ada.Text_IO.Unbounded_IO.Put_Line(Message);
         or
            -- Pick a timeout that makes sense.  Longer timeouts 
            -- give better CPU usage during idle times, but also means
            -- the program might not end immediately. 10ms or 1 second
            -- might be fine for general use
            delay 1.0;
         end select;

      end loop;

      Ada.Text_IO.Put_Line("Main task closed, closing Logger");

   end Logger;

   procedure Put_Line(Message : String) is 
   begin
      Messages.Enqueue(To_Unbounded_String(Message));
   end Put_Line;

end Logging;
...