J'essaie d'implémenter une barrière dans Ada qui a des fonctionnalités similaires à pthread_barrier_wait de C. Ada 2012 a Ada.Synchronous_Barriers mais ce n'est pas disponible sur mon système (gnu-gnat sur Debian Lenny). Plus précisément, comment puis-je obtenir toutes les tâches en attente d'une barrière en même temps et, idéalement, faire qu'une de ces tâches fasse quelque chose de spécial, sans utiliser Ada 2012? Voici une implémentation très sous-optimale. Quelle pourrait être une meilleure approche?Ada: comportement comme pthread_barrier_wait?
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;
sortie du programme:
$ ./foobar
3
1
2
3
1
2
3
2
1
Ce paquet Ada2012 est apparu dans GCC 4.7. Il est certainement présent dans GNAT GPL 2015 - je voudrais juste télécharger le paquet source et l'utiliser (probablement mieux le renommer en 'Ada_Synchronous_Barriers', pour arrêter le compilateur). Vous pouvez dire quelle version de GNAT vous avez sur votre système par 'gnatls -v', soit dit en passant. –
@SimonWrite Grande solution pratique. gnatls montre 4.6 sur ma machine – aquilonis