Ada 中的多线程
Multithreading in Ada
我正在学习 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;
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;
正如我已经提到的,如果我调用 P_EXECUTE_NO_ENTRY
,输出将是无序的并且任务与主线程分离。另一方面 *P_EXECUTE_ENTRY(to : in Integer)
导致阻塞过程调用,输出就像一个不使用任务的应用程序。
在 Ada 中如何并发执行具有条目的任务?
此外,我是否也必须取消分配任务? (网上的例子没做)
任务在集合点期间同步(即只要您在 accept
语句内)。
通常,您会将 accept
语句限制为复制传递的参数 to/from 包含 accept
语句的任务:
accept Start (Steps : in Positive) do
Count := Steps;
end Start;
for I in 1 .. Count loop
...
当你说
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;
调用方在 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;
至于取消分配任务 - 大多数终止的程序都不会打扰,因为操作系统会在进程退出时取消分配内存。在这种情况下,您可能不会在任务实际终止之前抽空解除分配;取消分配 运行 任务可能会导致意外行为。我认为如何管理这应该是一个不同的问题。
我正在学习 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;
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;
正如我已经提到的,如果我调用 P_EXECUTE_NO_ENTRY
,输出将是无序的并且任务与主线程分离。另一方面 *P_EXECUTE_ENTRY(to : in Integer)
导致阻塞过程调用,输出就像一个不使用任务的应用程序。
在 Ada 中如何并发执行具有条目的任务?
此外,我是否也必须取消分配任务? (网上的例子没做)
任务在集合点期间同步(即只要您在 accept
语句内)。
通常,您会将 accept
语句限制为复制传递的参数 to/from 包含 accept
语句的任务:
accept Start (Steps : in Positive) do
Count := Steps;
end Start;
for I in 1 .. Count loop
...
当你说
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;
调用方在 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;
至于取消分配任务 - 大多数终止的程序都不会打扰,因为操作系统会在进程退出时取消分配内存。在这种情况下,您可能不会在任务实际终止之前抽空解除分配;取消分配 运行 任务可能会导致意外行为。我认为如何管理这应该是一个不同的问题。