Discussion:
Question sur les tasks
(trop ancien pour répondre)
Stéphane Rivière
2023-10-17 15:57:23 UTC
Permalink
Bonjour à toutes et tous,

Je ne connais rien aux tâches Ada.

Vite fait, afin de baisser le timeout de DB MySQL (par défaut à 8
heures, que je baisserai bien à 1h30 pour réduire les ressources des
connexions laissées ouvertes pour rien), je 'codouille' ceci dans le
main de l'app. utilisateur... Msg.Std ou Sql.Ping ne sont pas réentrants
mais comme c'est de l'affichage de log ou de la pure lecture de DB, je
ne m'en fait pas pour l'instant...

L'appel à C balaye la table des DB ouvertes et envoie un "SELECT 1"
bidon à toutes les DB qui le nécessitent (donc pas les SQLite par exemple).

Mais au démarrage de l'applic, pour que la line B affiche le message de
log :

TestGui.SQL_Ping > Armed for 3600s cycles

Il faut que je mette une ligne A avec un appel à delay...

J'aimerai bien comprendre le truc (et baisser mon ignorance).


---------------------------------------
task SQL_Ping;

task body SQL_Ping is
Delay_Value : Duration := 3600.0; -- Wait 1 hour between pings
begin
A delay 0.1; -- Mandatory to displaying the message below
B Msg.Std ("TestGui.SQL_Ping > Armed for " &
Trim_Left (Field_By_Index (From_Latin_1 (Duration'Image
(Delay_Value)), 1, ".")) & "s cycles");
while True loop
delay Delay_Value;
Msg.Dbg ("TestGui.SQL_Ping > Sent");
C Sql.Ping;
end loop;
end SQL_Ping;

---------------------------------------

Merci d'avance (et généralement merci à la communauté, vous me faites
bien progresser :).
--
Stéphane Rivière
Ile d'Oléron - France
Pascal Obry
2023-10-17 19:51:11 UTC
Permalink
Stéphane,
Post by Stéphane Rivière
Merci d'avance (et généralement merci à la communauté, vous me faites
bien progresser :).
Pas certain, mais quelques questions:

1. Est-ce sous Windows ?
2. Il semble que le système de tâche ne soit pas préemptif d'où ma
question 1. Du coup le delay donnerait la main à une autre tâche dans
le système ?
3. Est-ce que Msg comporte du tasking ?

Voilà, pour le moment.
Stéphane Rivière
2023-10-18 06:33:11 UTC
Permalink
Bonjour Pascal,
Post by Pascal Obry
1. Est-ce sous Windows ?
Non... à la boite, plus de doze sur les stations depuis 2017...

GNU/Linux Ubuntu 22.04 LTS avec FSF 11 (le 12 est buggué pour Gnoga, 13
à tester mais le bug ne serait pas corrigé si l'on en croit les
discussions sur les forums FSF)
Post by Pascal Obry
2. Il semble que le système de tâche ne soit pas préemptif d'où ma
question 1. Du coup le delay donnerait la main à une autre tâche dans
le système ?
Windows NT est préemptif...

En tout cas, clairement, delay fait quelque chose :)
Post by Pascal Obry
3. Est-ce que Msg comporte du tasking ?
Non.

Juste une fonction de log basique, qui écrit sur l'écran et dans un
fichier... Il faudrait que je l'améliore pour qu'elle soit task aware
mais je manque de temps pour l'instant et ce n'est pas critique (Gnoga
gère les multi-connexions et cette fonction de "ping" n'est active
qu'une fois pas heure et pour les DB MySQL uniquement).
Post by Pascal Obry
Voilà, pour le moment.
--
Stéphane Rivière
Ile d'Oléron - France
Pascal Obry
2023-12-07 18:17:01 UTC
Permalink
Bonjour Stéphane,
Post by Stéphane Rivière
Windows NT est préemptif...
Pas 100% dans toutes les implémentations, je pense que 
"select ... then abort" ne fonctionne pas correctement sous Windows par
exemple.

Désolé pour la réponse super tardive :)
--
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://photos.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B
pehache
2023-12-08 11:27:02 UTC
Permalink
Post by Blady
Bonjour Stéphane,
Post by Stéphane Rivière
Windows NT est préemptif...
Pas 100% dans toutes les implémentations,
Windows est préemptif depuis Win95 dans la branche "grand-public" et
depuis toujours dans la branche NT. Par contre le préemptif ne marche pas
sur les applis 16 bits qui tournent en mode compatibilité, mais ça ne
doit plus être très courant aujourdhui :)
Pascal Obry
2023-12-08 15:30:35 UTC
Permalink
Post by pehache
Post by Blady
Bonjour Stéphane,
Post by Stéphane Rivière
Windows NT est préemptif...
Pas 100% dans toutes les implémentations,
Windows est préemptif depuis Win95 dans la branche "grand-public" et
depuis toujours dans la branche NT. Par contre le préemptif ne marche pas
sur les applis 16 bits qui tournent en mode compatibilité, mais ça ne
doit plus être très courant aujourdhui :)
Oui, jusque là je suis d'accord, mais la question était sur le tasking
et il y a des restrictions sur le "then abort" sur Windows dans
l'implémentation de GNAT. Il n'est généralement pas possible de faire
un "asynchronous abort of tasks" sur Windows.
--
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://photos.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B
pehache
2023-12-08 16:11:17 UTC
Permalink
Post by Pascal Obry
Post by pehache
Post by Blady
Bonjour Stéphane,
Post by Stéphane Rivière
Windows NT est préemptif...
Pas 100% dans toutes les implémentations,
Windows est préemptif depuis Win95 dans la branche "grand-public" et
depuis toujours dans la branche NT. Par contre le préemptif ne marche pas
sur les applis 16 bits qui tournent en mode compatibilité, mais ça ne
doit plus être très courant aujourdhui :)
Oui, jusque là je suis d'accord, mais la question était sur le tasking
et il y a des restrictions sur le "then abort" sur Windows dans
l'implémentation de GNAT. Il n'est généralement pas possible de faire
un "asynchronous abort of tasks" sur Windows.
Oui, OK, je réagissais uniquement par rapport à Windows, je ne connais
pas grand chose des tasks d'ADA

D'ailleurs pour mon information elles se traduisent comment en pratique ?
Par des threads, ou par des process séparés ?
Pascal Obry
2023-12-08 16:50:48 UTC
Permalink
Post by pehache
Par des threads, ou par des process séparés ?
Par des threads.
--
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://photos.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B
DrPi
2023-10-17 21:06:37 UTC
Permalink
Salut Stéphane,
Post by Stéphane Rivière
Bonjour à toutes et tous,
Msg.Std ou Sql.Ping ne sont pas réentrants
mais comme c'est de l'affichage de log ou de la pure lecture de DB, je
ne m'en fait pas pour l'instant...
L'appel à C balaye la table des DB ouvertes et envoie un "SELECT 1"
bidon à toutes les DB qui le nécessitent (donc pas les SQLite par exemple).
Mais au démarrage de l'applic, pour que la line B affiche le message de
TestGui.SQL_Ping > Armed for 3600s cycles
Il faut que je mette une ligne A avec un appel à delay...
J'aimerai bien comprendre le truc (et baisser mon ignorance).
---------------------------------------
   task SQL_Ping;
   task body SQL_Ping is
      Delay_Value : Duration := 3600.0;  -- Wait 1 hour between pings
   begin
A      delay 0.1; --  Mandatory to displaying the message below
B      Msg.Std ("TestGui.SQL_Ping > Armed for " &
               Trim_Left (Field_By_Index (From_Latin_1 (Duration'Image
(Delay_Value)), 1, ".")) & "s cycles");
      while True loop
         delay Delay_Value;
         Msg.Dbg ("TestGui.SQL_Ping > Sent");
C        Sql.Ping;
      end loop;
   end SQL_Ping;
---------------------------------------
Je ne vois pas de problème lié au tasking de Ada.
Par contre, je vois un problème de tasking au sens général
(indépendamment du langage).

Tu dis que la procédure Msg.Std n'est pas réentrante mais que ce n'est
pas un problème. Or Msg.Std est appelée à partir de la tâche SQL_Ping et
sûrement à partir d'autres tâches comme la tâche principale. A partir de
là, il y a un risque de dysfonctionnement.
Par exemple, si Msg.Std est appelée par la tâche principale puis, avant
qu'elle ne se termine, est également appelée par la tâche SQL_Ping, il y
a problème puisque la fonction n'est pas réentrante.
Le fait d'ajouter un délai au début de la tâche SQL_Ping permet à la
fonction Msg.Std de se terminer dans la tâche principale avant d'être
appelée dans SQL_Ping. Et tout semble fonctionner parfaitement. Mais ce
n'est qu'une illusion. Il est fort probable que dans d'autres conditions
de fonctionnement (charge processeur différente, code modifié...), le
délai doive être modifié.

Une fonction/procédure appelée à partir de plusieurs tâches DOIT être
conçue pour ça (protection avec un mutex, utilisation un objet protégé...).

Nicolas
Stéphane Rivière
2023-10-18 06:33:14 UTC
Permalink
Bonjour Nicolas,
Post by DrPi
Tu dis que la procédure Msg.Std n'est pas réentrante mais que ce n'est
pas un problème. Or Msg.Std est appelée à partir de la tâche SQL_Ping et
sûrement à partir d'autres tâches comme la tâche principale. A partir de
là, il y a un risque de dysfonctionnement.
La routine de task est dans la déclaration du main... Et appelle une
fois par heure Sql.Ping (jamais appelée par ailleurs, qui envoie une
requête SQL bidon de lecture pour réarmer le timeout de MySQL) et
Msg.Std (appelée partout, écrit sur la console et dans un fichier).
Post by DrPi
Par exemple, si Msg.Std est appelée par la tâche principale puis, avant
qu'elle ne se termine, est également appelée par la tâche SQL_Ping, il y
a problème puisque la fonction n'est pas réentrante.
Oui, ça va mettre le souk sur l'écran et dans le fichier.
Post by DrPi
Le fait d'ajouter un délai au début de la tâche SQL_Ping permet à la
fonction Msg.Std de se terminer dans la tâche principale avant d'être
appelée dans SQL_Ping. Et tout semble fonctionner parfaitement. Mais ce
n'est qu'une illusion. Il est fort probable que dans d'autres conditions
de fonctionnement (charge processeur différente, code modifié...), le
délai doive être modifié.
J'ai testé différentes valeurs, de 100ms à 5s, ça ne change rien.
Post by DrPi
Une fonction/procédure appelée à partir de plusieurs tâches DOIT être
conçue pour ça (protection avec un mutex, utilisation un objet protégé...).
C'est la prochaine étape. Là, c'était du 'gaffer' pour éviter d'avoir
une appli fonctionnelle (au niveau Web, puisque Gnoga ping régulièrement
le navigateur - on est en websocket, pas en html -) mais pas au niveau
de la connexion SQL (par manque d'activité). Le lendemain matin, ça ne
fait pas cossu :)

Je compte bien me perfectionner en Ada avec les tasks :)
--
Stéphane Rivière
Ile d'Oléron - France
DrPi
2023-10-18 16:55:05 UTC
Permalink
Salut Stéphane,
Post by Stéphane Rivière
Post by DrPi
Une fonction/procédure appelée à partir de plusieurs tâches DOIT être
conçue pour ça (protection avec un mutex, utilisation un objet protégé...).
C'est la prochaine étape. Là, c'était du 'gaffer' pour éviter d'avoir
une appli fonctionnelle (au niveau Web, puisque Gnoga ping régulièrement
le navigateur - on est en websocket, pas en html -) mais pas au niveau
de la connexion SQL (par manque d'activité). Le lendemain matin, ça ne
fait pas cossu :)
Si tu veux facilement protéger Msg.Std des accès concurrents par
plusieurs tâches, tu peux (temporairement) utiliser un mutex.

Un mutex de base ça se définit comme ça :

protected type Mutex is
entry Lock;
procedure Release;
private
Owned : Boolean := False;
end Mutex;

protected body Mutex is
entry Lock when not Owned is
begin
Owned := True;
end Seize;
procedure Release is
begin
Owned := False;
end Release;
end Mutex;

En début de fonction, un appel à Mutex.Lock.
En fin de fonction, un appel à Mutex.Release.
Le mutex doit être déclaré de façon statique (global par exemple).

Sinon, une autre piste : Peut être que le package Msg nécessite une
initialisation (faite par la tâche principale ?) qui n'est pas encore
faite/terminée lors de l'appel à Msg.Std dans la tâche SQL_Ping. Le
délai permet à l'appel de Msg.Std de se faire après l'initialisation.

Nicolas
Stéphane Rivière
2023-10-19 13:41:50 UTC
Permalink
Bonjour Nicolas,
Post by DrPi
Si tu veux facilement protéger Msg.Std des accès concurrents par
plusieurs tâches, tu peux (temporairement) utiliser un mutex.
Super idée :)

Et l'implémentation gaze !

Dans v22.ads :

protected type Mutex is
entry Lock;
procedure Release;
end Mutex;

private

Owned : Boolean := False;

Dans v22.adb :

package body v22 is

use v22;

protected body Mutex is
entry Lock when not Owned is
begin
Owned := True;
end Lock;
procedure Release is
begin
Owned := False;
end Release;
end Mutex;


Dans la fonction privée qui factorise tous les Msg.Std/Dbg/Err :

procedure Put (Line_In : String;
Line_Level : String;
Title_On : Boolean := False) is
Line : String := Line_In;
Line_Disk : String := Line;
Line_Task : String := "";
Ansi_Begin : String := "";
Ansi_End : String := "";
M : Mutex;
begin
M.Lock;

.../...

M.Release;
end Put;

Merci Nicolas !!!
--
Stéphane Rivière
Ile d'Oléron - France
DrPi
2023-10-19 16:59:06 UTC
Permalink
Bonjour Stéphane,
Post by Stéphane Rivière
procedure Put (Line_In : String;
               Line_Level : String;
               Title_On : Boolean := False) is
      Line : String := Line_In;
      Line_Disk : String := Line;
      Line_Task : String := "";
      Ansi_Begin : String := "";
      Ansi_End : String := "";
      M : Mutex;
   begin
      M.Lock;
      .../...
      M.Release;
   end Put;
!!! Implémenté comme ça, le mutex ne protège rien !!!

Lorsque le mutex est déclaré dans la fonction, un nouveau mutex est créé
à chaque appel de la fonction. Il ne sert donc à rien.

Il faut que le mutex soit déclaré au niveau global. Au début du "package
body Msg" par exemple.

Nicolas
J-P. Rosen
2023-10-19 21:57:56 UTC
Permalink
Je n'ai pas suivi toute la discussion, mais tu peux être intéressé par
mon composant "protection":
https://adalog.fr/fr/composants.html#Protection
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
https://www.adalog.fr https://www.adacontrol.fr
Stéphane Rivière
2023-10-20 07:46:22 UTC
Permalink
Post by J-P. Rosen
Je n'ai pas suivi toute la discussion, mais tu peux être intéressé par
https://adalog.fr/fr/composants.html#Protection
Oui, clairement... Du coup j'ai été voir l'exemple d'implémentation
Tracer. J'ai eu soudainement l'impression de n'avoir jamais codé en Ada
(rien d'étonnant jusque là :) Alors je vais regarder tout ça de près car
Tracer me semble extrêmement intéressant, autant par ses fonctionnalités
que par son implémentation.

PS

Petite typo puisque maintenant tu as renommé le package Tracer...

Have a look at package ***Debug***

Q: Where can I find examples of uses of this package?
A: Have a look at package Debug, also available from Adalog's components
page. Actually, the need for package Protection appeared when designing
Debug, and we decided later to make it a software component of its own.
--
Stéphane Rivière
Ile d'Oléron - France
J-P. Rosen
2023-10-20 08:38:25 UTC
Permalink
Post by Stéphane Rivière
Petite typo puisque maintenant tu as renommé le package Tracer...
Have a look at package ***Debug***
Q: Where can I find examples of uses of this package?
A: Have a look at package Debug, also available from Adalog's components
page. Actually, the need for package Protection appeared when designing
Debug, and we decided later to make it a software component of its own.
Oups, merci. Effectivement, le package s'appelait autrefois Debug, mais
il y avait un peu trop de packages dans la nature (y compris un
d'AdaCore) avec ce nom...
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
https://www.adalog.fr https://www.adacontrol.fr
J-P. Rosen
2023-10-20 16:24:37 UTC
Permalink
Post by Stéphane Rivière
Petite typo puisque maintenant tu as renommé le package Tracer...
Have a look at package ***Debug***
Oups merci, c'est corrigé maintenant
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
https://www.adalog.fr https://www.adacontrol.fr
Stéphane Rivière
2023-10-20 07:31:09 UTC
Permalink
Post by DrPi
Lorsque le mutex est déclaré dans la fonction, un nouveau mutex est créé
à chaque appel de la fonction. Il ne sert donc à rien.
Merci Nicolas, j'ai buggué... Créé le type Mutex là où il fallait mais M
aurait du être instancié au même endroit...
C'est corrigé...
Post by DrPi
Il faut que le mutex soit déclaré au niveau global. Au début du "package
body Msg" par exemple.
Tout déclaré au niveau du package racine v22...
--
Stéphane Rivière
Ile d'Oléron - France
Blady
2023-10-18 19:22:32 UTC
Permalink
Post by Stéphane Rivière
Bonjour à toutes et tous,
Je ne connais rien aux tâches Ada.
Vite fait, afin de baisser le timeout de DB MySQL (par défaut à 8
heures, que je baisserai bien à 1h30 pour réduire les ressources des
connexions laissées ouvertes pour rien), je 'codouille' ceci dans le
main de l'app. utilisateur... Msg.Std ou Sql.Ping ne sont pas réentrants
mais comme c'est de l'affichage de log ou de la pure lecture de DB, je
ne m'en fait pas pour l'instant...
L'appel à C balaye la table des DB ouvertes et envoie un "SELECT 1"
bidon à toutes les DB qui le nécessitent (donc pas les SQLite par exemple).
Mais au démarrage de l'applic, pour que la line B affiche le message de
TestGui.SQL_Ping > Armed for 3600s cycles
Il faut que je mette une ligne A avec un appel à delay...
J'aimerai bien comprendre le truc (et baisser mon ignorance).
---------------------------------------
   task SQL_Ping;
   task body SQL_Ping is
      Delay_Value : Duration := 3600.0;  -- Wait 1 hour between pings
   begin
A      delay 0.1; --  Mandatory to displaying the message below
B      Msg.Std ("TestGui.SQL_Ping > Armed for " &
               Trim_Left (Field_By_Index (From_Latin_1 (Duration'Image
(Delay_Value)), 1, ".")) & "s cycles");
      while True loop
         delay Delay_Value;
         Msg.Dbg ("TestGui.SQL_Ping > Sent");
C        Sql.Ping;
      end loop;
   end SQL_Ping;
---------------------------------------
Merci d'avance (et généralement merci à la communauté, vous me faites
bien progresser :).
Bonjour Stéphane,

La déclaration de SQL_Ping à ce niveau fait qu'elle démarre dès son
élaboration.
Et donc sans doute avant l'initialisation de quelques codes utiles à
Msg.Std que permet l'ajout du delay.

Ce qui rend le fonctionnement très dépendant de beaucoup de choses :-(

Du coup, dans ces cas là, j'ajoute toujours un "accept Start" (à la
place de ton "delay 0.1;") qui va attendre un appel à "Start" que tu vas
pouvoir mettre dans ton code une fois que tout a été initialisé.

Autres astuces:
. pour une boucle infinie en Ada -> tout simplement "loop ... end loop;"
. pour prendre directement l'image du type Duration avec UXStrings ->
déclarer la fonction :
function Image is new UXStrings.Conversions.Fixed_Point_Image (Duration);

HTH, Pascal.
Stéphane Rivière
2023-10-19 13:40:44 UTC
Permalink
Bonjour Pascal,
Post by Blady
La déclaration de SQL_Ping à ce niveau fait qu'elle démarre dès son
élaboration.
D'accord... je comprends.
Post by Blady
Et donc sans doute avant l'initialisation de quelques codes utiles à
Msg.Std que permet l'ajout du delay.
Ahhhh...
Post by Blady
Ce qui rend le fonctionnement très dépendant de beaucoup de choses :-(
Du coup, dans ces cas là, j'ajoute toujours un "accept Start" (à la
place de ton "delay 0.1;") qui va attendre un appel à "Start" que tu vas
pouvoir mettre dans ton code une fois que tout a été initialisé.
Trop bien tes astuces !!! Tout implémenté, ça gaze nickel e!

Grand merci pour ton aide...


----------------------------------------------------------------------------
function Image is new UXStrings.Conversions.Fixed_Point_Image
(Duration);


----------------------------------------------------------------------------
task SQL_Ping is
entry Start;
end SQL_Ping;

task body SQL_Ping is
Delay_Value : Duration := 3600.0; -- Wait 1 hour between pings
begin
accept Start;

Msg.Std ("TestGui.SQL_Ping > Armed for " & Trim_Left
(Field_By_Index (Image (Delay_Value), 1, ".")) & "s cycles");

loop
delay Delay_Value;
Msg.Dbg ("TestGui.SQL_Ping > Sent");
Sql.Ping;
end loop;
end SQL_Ping;

-------------------------------------------------------------------------------
begin

if Ini.App then

Gnoga.Log
("------------------------------------------------------------------------");
-- To ease gnoga log file reading
Gnoga.Log ("Starting Gnoga server");
Msg.Std ("TestGui.On_Connect > Starting Gnoga server");

Gui.Setup (On_User_Connect => Usr.Connect'Unrestricted_Access,
Host => App_Config_Datas.Connection_Domain,
Port => App_Config_Datas.Connection_Port,
Boot => "boot_jqueryui.html",
Title => App_Name_Gui,
Server_Closed_Content => "<b>" & App_Name_Gui & " >
Déconnexion serveur</b>");

Gui.Set_Application_Icon ("ico-widget.png");
Gui.Set_User_Icon ("ico-user.png");

Gui.Set_Login (Off); -- Application access is protected by a
login screen. Set-it to Off to ease tests and debugging

-- Application menu hierarchy
Gui.Header_Set_Root ("App_Menu", App_Name_Gui,
On_Mgt'Unrestricted_Access);
Gui.Header_Application_Menu_Add ("Mgt", "Gestion", "App_Menu",
On_Mgt'Unrestricted_Access);
Gui.Header_Application_Menu_Add ("Adm", "Administration",
"App_Menu", On_Adm'Unrestricted_Access);

-- Start Sql_Ping task
SQL_Ping.Start;

-- Application message loop
Gnoga.Application.Multi_Connect.Message_Loop;

end if;
--
Stéphane Rivière
Ile d'Oléron - France
Loading...