Я пытаюсь реализовать барьер в Ada, который имеет аналогичную функциональность для pthread_barrier_wait C. Ada 2012 имеет Ada.Synchronous_Barriers, но это недоступно в моей системе (gnu-gnat на debian lenny).Ada: поведение, подобное pthread_barrier_wait?
В частности, как я могу получить все задачи ожидания, которые будут выпущены из барьера в то же время, и, в идеале, одна из этих задач сделает что-то особенное, не используя Ada 2012? Ниже приведена очень малооптимальная реализация. Что может быть лучшим подходом?
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure foobar is
protected Synchronizer is
entry Ready_For_Action; -- prepares for tasks to wait at barrier
entry Wait_For_Release; -- barrier
-- do work here
entry Done; -- signals that all tasks are done
entry Wait_For_Others; -- prepares for prepare to wait at barrier
private
ready, active: Natural := 0;
-- two state variables seem to be needed as entry conditions can't
-- safely modify the condition variable as that influences wait
-- state in other tasks
end Synchronizer;
NUM_OBJECTS: constant := 3;
protected body Synchronizer is
entry Ready_For_Action when active = 0 is
begin
ready := ready + 1;
end Ready_For_Action;
--
entry Wait_For_Release when ready = NUM_OBJECTS is
begin
active := active + 1;
end Wait_For_Release;
--
entry Done when active = NUM_OBJECTS is
begin
ready := ready - 1;
end Done;
--
entry Wait_For_Others when ready = 0 is
begin
active := active - 1;
end wait_for_others;
--
end Synchronizer;
task type Foo(N: Natural);
task body Foo is
id: Natural := N;
begin
for iter in 1..3 loop
Synchronizer.Ready_For_Action;
Synchronizer.Wait_For_Release;
-- task N doing something special
if id = 1 then new_line; end if;
-- do stuff here
delay 0.1;
put(id); new_line;
-- re-sync
Synchronizer.Done;
Synchronizer.Wait_For_Others;
end loop;
end Foo;
Task1: Foo(1);
Task2: Foo(2);
Task3: Foo(3);
begin
Null;
end foobar;
выход программы:
$ ./foobar
3
1
2
3
1
2
3
2
1
Этот пакет Ada2012 появился в GCC 4.7. Это, безусловно, присутствует в GNAT GPL 2015 - я просто загрузил исходный пакет и использовал его (возможно, лучше всего переименовать его в «Ada_Synchronous_Barriers», чтобы остановить путаницу компилятора). Вы можете сказать, какую версию GNAT у вас есть в вашей системе, например, gnatls -v'. –
@SimonWrite Отличное решение для pracitcal. gnatls показывает 4.6 на моей машине – aquilonis