Как повторно инициализировать задачи в ADA

У меня простой на вид вопрос:

У меня есть несколько задач, работающих одновременно в ADA. Вместе они создают симуляцию выборов в воображаемой стране. Я хотел бы перезапустить всю симуляцию, если возникнет определенное условие. Поэтому я хочу прервать каждую задачу и перезапустить их. Как это сделать без пересоздания задач? Я уверен, что есть лучший способ, но я не могу его найти. Кстати, задачи находятся в массиве. Заранее спасибо!!

with Ada.Text_IO;
use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;

procedure Election is

type RandNum is new Integer range 1..100;

package RandInt is new Ada.Numerics.Discrete_Random(RandNum);
use RandInt;

task type Youngster;
task type DarkSide;

task type Guard;

NowVoting: Boolean := False;
YoungsterNum: Positive := 7;
DarkNum: Positive := 3;
G: Generator;

type PartyType is array (Positive range 1..3) of Natural;

task Place is
entry Vote(Num: in RandNum; Cheat: in Boolean);
end Place;

protected Collector is
procedure GoHome;
procedure GuardIn;
procedure GuardOut;
procedure Arrest;
function HowManyArrested return Natural;
function HowManyGuards return Natural;
function HowMany return Integer;
private
Home: Integer := 0;
Guards: Natural := 2;
Arrested: Natural := 0;
end Collector;

task body Place is
Party: PartyType := (0,0,0);
Guard1: Guard;
Guard2: Guard;
Votes: Natural := 0;
begin

Put_Line("-----------------------------------------------");
Put_Line("         A SZAVAZĂS KEZDETÉT VESZI");
Put_Line("-----------------------------------------------");
while Collector.HowMany /= YoungsterNum and Collector.HowManyArrested /= DarkNum     loop


        accept Vote(Num: in RandNum; Cheat: in Boolean) do

            NowVoting := True;

            if Num < 33 then
                Party(1) := Party(1) + 1;
            elsif Num > 33 and Num < 66 then
                Party(2) := Party(2) + 1;
            else
                Party(3) := Party(3) + 1;
            end if;

            Votes := Votes + 1;

        delay 2.0;

            Put("Ifjonctanácsok Intergalaktikus Szövetsége: ");
            Put_Line(Integer'Image(Party(1)));
            Put("ĹfelsĂ©ge Leghűbb EllenzĂ©ke: ");
            Put_Line(Integer'Image(Party(2)));
            Put("Demokratikus Ellenzék: ");
            Put_Line(Integer'Image(Party(3)));
            Put("Ă–sszesĂ­tve: ");
            Put_Line(Natural'Image(Votes));
            Put_Line("-----------------------------------------------");
            if Cheat then
                Put_Line("!!! C S A L Ă S !!!");
            end if;

            NowVoting := False;
        end;

end loop;


if (Votes-(YoungsterNum + DarkNum)) > ((YoungsterNum + DarkNum) / 20) then
    Put_Line("A szavazást meg kell ismételni!");
end if;

end Place;

task body Youngster is
Num: RandNum;
Success: Boolean := False;
Time: Natural := 0;
begin

Reset(G);
Num := Random(G);

while Success = False loop
while Time /= 6 and Success = False loop
    if NowVoting = False and (Collector.HowManyGuards = 2 
                          or Collector.HowManyGuards = 0) then
        Place.Vote(Num, False);
        Success := True;
        Collector.GoHome;
    else
        Time := Time + 1;
        delay 1.0;
    end if;

end loop;

if Success = False then
    Num := Random(G);
    Time := 0;
end if;
end loop;

end Youngster;

task body DarkSide is
Num: RandNum;
Success: Boolean := False;
Time: Natural := 0;
begin
delay 2.0;
Reset(G);

loop
    Num := Random(G);

    if Collector.HowManyGuards = 0 and Collector.HowManyArrested /= DarkNum then
        Place.Vote(Num, True);
        delay 2.0;
    else
        Collector.Arrest;
        Put_Line("!!! L E A T A R T Ă“ Z T A T Ă S !!!");
        exit;
    end if;
end loop;

end DarkSide;

protected body Collector is
procedure GoHome is
begin
    Home := Home + 1;
end GoHome;

procedure GuardOut is
begin
    Guards := Guards - 1;
end GuardOut;

procedure GuardIn is
begin
    Guards := Guards + 1;
end GuardIn;

procedure Arrest is
begin
    Arrested := Arrested + 1;
end Arrest;

function HowManyArrested return Natural is
begin
    return Arrested;
end HowManyArrested;

function HowManyGuards return Natural is
begin
    return Guards;
end HowManyGuards;

function HowMany return Integer is
begin
    return Home;
end HowMany;
end Collector;

task body Guard is
Num: RandNum;
begin
Reset(G);
while Collector.HowMany /= YoungsterNum  and Collector.HowManyArrested /= DarkNum loop
    Num := Random(G);
    if Collector.HowManyGuards = 2 then
        if Num <= 30 then
            Collector.GuardOut;
            Put_Line("(((Ĺr kiment szabályosan!)))");
            delay 10.0;
            Collector.GuardIn;
            Put_Line("(((Ĺr visszatĂ©rt!)))");
            delay 4.0;
        end if;
    else
        if Num <= 25 then
            Collector.GuardOut;
            Put_Line("(((Ĺr kiment szabálytalanul!)))");
            delay 10.0;
            Collector.GuardIn;
            Put_Line("(((Ĺr visszatĂ©rt!)))");
            delay 4.0;
        end if;
    end if;
end loop;
end Guard;

Youngsters: array (1..YoungsterNum) of Youngster;
Dark: array(1..DarkNum) of DarkSide;

begin
null;
end Election;

Строки put_lines на венгерском языке, это не имеет значения. Итак, что я хотел бы сделать, это когда это правда:

if (Votes-(YoungsterNum + DarkNum)) > ((YoungsterNum + DarkNum) / 20) then

то я хочу, чтобы все это началось снова:

Youngsters: array (1..YoungsterNum) of Youngster;
Dark: array(1..DarkNum) of DarkSide;
task Place is
entry Vote(Num: in RandNum; Cheat: in Boolean);
end Place;

И, конечно же, два Стража на Месте, это само собой. Я надеюсь, что это ясно.


person Gábor Birkás    schedule 31.05.2013    source источник
comment
Это описание довольно расплывчато, так как решение будет зависеть от того, как реализован избирательный функционал в задачах. Расширьте свой вопрос, чтобы описать структуру того, что происходит в задаче, а затем можно предложить некоторые предложения. Конечно, можно сбросить задачу, если это разрешено.   -  person Marc C    schedule 31.05.2013
comment
Есть ли причина не добавлять запись Restart к каждой задаче, которая устанавливает ее в исходное состояние?   -  person user_1818839    schedule 01.06.2013
comment
Потому что задачи не заканчивают свою работу одновременно, а при перезапуске симуляции они должны начинаться вместе (вроде). Если бы я добавил запись Restart для каждой задачи, это привело бы к тому, что некоторые задачи работали с неправильными данными, потому что другие уже изменили их. Ответ, который я нашел, принципиально отличается, но он также должен что-то делать с записью. Я опубликую это как ответ на эту проблему.   -  person Gábor Birkás    schedule 02.06.2013


Ответы (2)


Если задача выборов в настоящее время представляет собой просто симуляцию выборов, обернутую в задачу, чтобы множественные выборы могли проходить параллельно:

-- Not compiled
task body Simulated_Elections is

begin
   Initialize_Electoral_Information;
   Determine_Candidates;
   Run_Election;
   Inaugurate;
end Simulated_Elections;

Тогда может быть достаточно просто поместить функциональность в цикл с выходом:

-- Still not compiled
task body Simulated_Elections is

begin
   loop
      select
         accept The_Voice_Of_The_People;
      or
         accept Tyranny_And_Dictatorship;
         exit;
      or
         terminate;
      end select;

      Initialize_Electoral_Information;
      Determine_Candidates;
      Run_Election;
      Inaugurate;
   end loop;
end Simulated_Elections;
person Marc C    schedule 31.05.2013

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

  1. Создайте защищенный объект.
  2. Добавьте к нему охраняемый вход. Запись должна разрешать вызовы только тогда, когда каждая задача завершила свою работу.
  3. Из каждой задачи, когда они будут готовы снова начать симуляцию, вызовите эту запись. Поскольку есть охранник, никакая задача не будет обслуживаться, пока каждая задача не вызовет эту охраняемую запись. (Я проверил это с помощью простой переменной счетчика Natural внутри закрытой части защищенного устройства.)
  4. Поэтому, когда последняя задача присоединяется к очереди, ожидающей записи, она позволяет им «проходить» одну за другой.
  5. Внутри записи, если вы хотите изменить переменные, используемые более чем одной задачей, вы должны сделать это в операторе if с условием «уже был выполнен вызов последней задачи». Это необходимо, потому что запись обслуживает задачи одну за другой, поэтому, когда первая выполняется и вы изменяете важные переменные (например, что-то, касающееся оператора защиты), другие задачи могут ждать в очереди бесконечно.

Надеюсь, я ясно выразился. Я думаю, что в других языках это называется циклическим барьером.

person Gábor Birkás    schedule 02.06.2013
comment
Небольшим улучшением шага 5 будет то, что переменные, которые используются более чем одной задачей, сами будут внутри защищенного типа. - person NWS; 03.06.2013
comment
@NWS Они находятся внутри того же защищенного объекта, что и охраняемая запись, но, я думаю, это ничего не меняет. О каком именно улучшении вы думали? - person Gábor Birkás; 03.06.2013
comment
Я только что перечитал ваш ответ. Моя ошибка - я перепутал защищенный объект и защищенную задачу, которые являются одним и тем же!. - person NWS; 03.06.2013
comment
@NWS Насколько мне известно, защищенный объект - это не задача, а единица, которая инкапсулирует элементы данных и предоставляет к ним доступ через подпрограммы и записи. - person Gábor Birkás; 03.06.2013
comment
Точно, отсюда и мое замешательство. - person NWS; 05.06.2013