Ada中的多线程

jan*_*anr 0 multithreading ada task

我正在学习Ada,我在理解并发模型方面遇到了一些问题.以下测试应用程序应创建3个并行运行的任务,并简单地打印一系列数字.如果我没有使用任务,entry那么一切都很好,但如果我使用条目,则程序调用块并且根本不会发生并发.

我知道有可能实现互斥和同步执行,但我无法理解如何分离任务,甚至可能创建其中的几个.

q_multithreading.ads:

package Q_MULTITHREADING is

  task type TASK_LOOP is
  end TASK_LOOP;

  type TASK_LOOP_ACCESS is access TASK_LOOP;

  --===========================================================================

  task type TASK_ENTRY_LOOP is
    entry P_ITERATE(to : in Integer);
  end TASK_ENTRY_LOOP;

  type TASK_ENTRY_LOOP_ACCESS is access TASK_ENTRY_LOOP;

  --===========================================================================

  procedure P_EXECUTE_NO_ENTRY;

  procedure P_EXECUTE_ENTRY(to : in Integer);

end Q_MULTITHREADING;
Run Code Online (Sandbox Code Playgroud)

q_multithreading.adb:

with Ada.Text_IO;

package body Q_MULTITHREADING is

  V_ID_COUNTER : Integer := 1;

  --===========================================================================

  task body TASK_LOOP is

    V_ID : Integer := -1;

  begin

    V_ID := V_ID_COUNTER;
    V_ID_COUNTER := V_ID_COUNTER + 1;

    for i in 1 .. 15 loop
      delay 0.1;
      Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " &
                             Integer'Image(i));
    end loop;

    V_ID_COUNTER := V_ID_COUNTER - 1;

  end TASK_LOOP;

  --===========================================================================

  task body TASK_ENTRY_LOOP is

    V_ID : Integer := -1;

  begin

    V_ID := V_ID_COUNTER;
    V_ID_COUNTER := V_ID_COUNTER + 1;

    accept P_ITERATE(to : in Integer) do
      for i in 1 .. to loop
        delay 0.1;
        Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " &
                               Integer'Image(i));
      end loop;
    end P_ITERATE;

    V_ID_COUNTER := V_ID_COUNTER - 1;

  end TASK_ENTRY_LOOP;

  --===========================================================================

  procedure P_EXECUTE_NO_ENTRY is

    V_TASK1, V_TASK2, V_TASK3 : TASK_LOOP_ACCESS;

  begin

    V_ID_COUNTER := 1;

    Ada.Text_IO.Put_Line("Starting task 1 ...");
    V_TASK1 := new TASK_LOOP;

    Ada.Text_IO.Put_Line("Starting task 2 ...");
    V_TASK2 := new TASK_LOOP;

    Ada.Text_IO.Put_Line("Starting task 3 ...");
    V_TASK3 := new TASK_LOOP;

  end P_EXECUTE_NO_ENTRY;

  --===========================================================================

  procedure P_EXECUTE_ENTRY(to : in Integer) is

    V_TASK1, V_TASK2, V_TASK3 : TASK_ENTRY_LOOP_ACCESS;

  begin

    V_ID_COUNTER := 1;

    V_TASK1 := new TASK_ENTRY_LOOP;
    Ada.Text_IO.Put_Line("Starting task 1 ...");
    V_TASK1.P_ITERATE(to); -- blocking

    V_TASK2 := new TASK_ENTRY_LOOP;
    Ada.Text_IO.Put_Line("Starting task 2 ...");
    V_TASK2.P_ITERATE(to - 5); -- blocking

    V_TASK3 := new TASK_ENTRY_LOOP;
    Ada.Text_IO.Put_Line("Starting task 3 ...");
    V_TASK3.P_ITERATE(to + 3); -- blocking

  end P_EXECUTE_ENTRY;

end Q_MULTITHREADING;
Run Code Online (Sandbox Code Playgroud)

正如我已经提到的,如果我调用P_EXECUTE_NO_ENTRY输出是无序的,并且任务与主线程分离.另一方面*P_EXECUTE_ENTRY(to : in Integer)导致阻塞过程调用,输出就像一个不使用任务的应用程序.

如何在Ada中同时执行条目的任务?

此外,我还必须解除分配任务吗?(来自网络的例子没有这样做)

Sim*_*ght 5

当你说

accept P_ITERATE(to : in Integer) do
  for i in 1 .. to loop
    delay 0.1;
    Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " &
                           Integer'Image(i));
  end loop;
end P_ITERATE;
Run Code Online (Sandbox Code Playgroud)

调用者被阻塞直到end P_ITERATE,所以整个循环完成后P_EXECUTE_ENTRY才能继续下一个任务.

要解决此问题,请将循环计数保存在任务变量中并执行以下循环accept:

accept P_ITERATE(to : in Integer) do
  count := to;
end P_ITERATE;
for i in 1 .. count loop
  delay 0.1;
  Ada.Text_IO.Put_Line("[" & Integer'Image(V_ID) & "] " &
                         Integer'Image(i));
end loop;
Run Code Online (Sandbox Code Playgroud)

至于解除分配任务 - 大多数终止的程序都不会打扰,因为操作系统会在进程退出时释放内存.在这种情况下,您可能无法在任务实际终止之前解除分配; 取消分配正在运行的任务可能会导致意外行为.我认为如何管理这应该是一个不同的问题.