Вы не должны вызывать «потенциально блокирующую операцию» изнутри защищенного объекта.Вызов Text_IO.Put
является потенциально блокирующей операцией.См. Раздел Справочного руководства Ada 9.5.1.Я удивлен, что ваш компилятор не жаловался, на самом деле.
В этой ситуации вы можете использовать одну задачу вместо защищенного объекта.
Например:
with Ada.Text_IO;
procedure Main is
type Matrix is array (Integer range <>, Integer range <>) of Integer;
task Safe_Printer is
entry Put (S: in String);
entry Put (M: in Matrix);
end Safe_Printer;
task body Safe_Printer is
S: access String;
M: access Matrix;
begin
loop
select
accept Put (S: in String) do
Safe_Printer.S := new String (S'Range);
Safe_Printer.S.all := S;
end;
Ada.Text_IO.Put_Line (S.all);
or
accept Put (M: in Matrix) do
Safe_Printer.M := new Matrix (M'Range (1), M'Range (2));
Safe_Printer.M.all := M;
end;
for I in M'Range (1) loop
for J in M'Range (2) loop
Ada.Text_IO.Put (Integer'Image (M (I, J)) & " ");
end loop;
Ada.Text_IO.New_Line;
end loop;
or
terminate;
end select;
end loop;
end Safe_Printer;
M: Matrix := ((1,2,3),
(4,5,6));
begin
Safe_Printer.Put (M);
end Main;
Дополнительным преимуществом этого подхода является то, что вызовы Text_IO.Put[_Line]
фактически выполняются параллельно с основной задачей.Недостатком является то, что (для безопасности) копируемая строка или матрица копируется.
Лучшая версия этого кода может использовать Unchecked_Deallocation
или Ada.Containers.Indefinite_Holders
для хорошей очистки после себя.
Бонусный вопрос: Как вы думаете, границы массива матрицы M
в Main
процедуре есть?