Cycle de vie d’un agent
Chaque agent gAgent suit un cycle de vie conforme à la spécification FIPA Agent Management (FIPA SC00023J). Ce cycle comprend neuf états et les transitions entre eux sont déclenchées soit par l’agent lui-même, soit par un signal externe depuis un autre processus.
États
Constante |
Valeur |
Description |
|---|---|---|
|
0 |
État initial avant toute construction. L’agent n’existe pas encore. |
|
1 |
L’objet C++ est construit, l” |
|
2 |
|
|
3 |
L’agent est enregistré auprès de l’AMS. Tous ses |
|
4 |
Tous les behaviours sont figés. L’agent reste en mémoire mais n’exécute rien. Il peut être réactivé via |
|
6 |
Pause temporaire, typiquement en attendant un message ou une ressource. Réveillable par |
|
8 |
État transitoire entre WAITING et ACTIVE : les behaviours reprennent, l’agent redevient actif. |
|
5 |
L’agent migre vers une autre station (Phase 2). Tous ses behaviours sont suspendus le temps de la migration. |
|
7 |
L’agent a terminé son travail, s’est désenregistré de l’AMS et du DF, et son processus a appelé |
Diagramme d’états
![digraph agent_lifecycle {
rankdir=TB;
node [shape=roundrectangle, style=filled, fontname="Helvetica", fontsize=11];
edge [fontname="Helvetica", fontsize=10];
UNKNOWN [label="UNKNOWN\n(0)", fillcolor="#e0e0e0"];
CREATED [label="CREATED\n(1)", fillcolor="#cce5ff"];
INITED [label="INITED\n(2)", fillcolor="#cce5ff"];
ACTIVE [label="ACTIVE\n(3)", fillcolor="#c3e6cb", shape=doublecircle];
SUSPENDED [label="SUSPENDED\n(4)", fillcolor="#fff3cd"];
TRANSIT [label="TRANSIT\n(5)", fillcolor="#ffeeba"];
WAITING [label="WAITING\n(6)", fillcolor="#fff3cd"];
WAKING [label="WAKING\n(8)", fillcolor="#d4edda"];
DELETED [label="DELETED\n(7)", fillcolor="#f8d7da", shape=doublecircle];
UNKNOWN -> CREATED [label="constructeur"];
CREATED -> INITED [label="init() / fork()"];
INITED -> ACTIVE [label="AMS::register()"];
ACTIVE -> SUSPENDED [label="doSuspend()"];
SUSPENDED -> ACTIVE [label="doActivate()"];
ACTIVE -> WAITING [label="doWait()"];
SUSPENDED -> WAITING [label="doWait()"];
WAITING -> WAKING [label="doWake()"];
WAKING -> ACTIVE [label="(automatique)"];
ACTIVE -> TRANSIT [label="doMove()"];
TRANSIT -> ACTIVE [label="(arrivée)"];
ACTIVE -> DELETED [label="doDelete()\nou fin behaviours"];
SUSPENDED -> DELETED [label="doDelete()"];
WAITING -> DELETED [label="doDelete()"];
TRANSIT -> DELETED [label="doDelete()"];
}](../_images/graphviz-b05829d0e30ef220248c11a0ab19fa4074ea4c47.png)
Transitions et méthodes
Méthode / Signal |
Transition |
Signal POSIX RT envoyé (si externe) |
|---|---|---|
|
→ ACTIVE |
|
|
→ SUSPENDED |
|
|
→ WAITING |
|
|
→ WAKING → ACTIVE |
|
|
→ TRANSIT |
|
|
→ DELETED |
|
Les transitions sont locales si la méthode est appelée depuis l’intérieur du processus de l’agent, ou par signal si appelée depuis l’extérieur (processus parent ou autre agent).
Cycle complet d’exécution
Voici ce qui se passe exactement quand agent.init() est appelé :
[PARENT] agent.init()
└─ fork()
└─ retourne immédiatement
[CHILD] _init()
├─ agentStatus = INITED
├─ thread : listener_extern_signals_Thread()
│ └─ écoute SIG_AGENT_DELETE / ACTIVE / SUSPEND…
├─ thread : control_Thread()
│ └─ traite les actions (runingThred on/off)
├─ thread : control_message()
│ └─ POSIX MQ /{8-char-id} (contrôle lifecycle)
│
├─ AMSClient::registerAgent() → agentStatus = ACTIVE
│
├─ setup() ← à implémenter : addBehaviour(...)
│
├─ thread par Behaviour
│ ├─ onStart()
│ ├─ loop : action() tant que done() == false
│ └─ onEnd()
│
├─ join() tous les threads behaviour
│
├─ takeDown() ← à implémenter : nettoyage
│
└─ doDelete()
├─ AMSClient::deregisterAgent()
├─ DFClient::deregisterAgent()
├─ mq_unlink(/{8-char-id}) # ferme la queue de contrôle
├─ acl_flush() # draine les PUSH ZeroMQ (linger)
└─ _exit(0)
Suspension et reprise des behaviours
La suspension agit sur un flag partagé runingThred protégé par un
std::mutex. Chaque thread behaviour attend sur une
std::condition_variable :
// Dans exthread() — boucle interne de chaque Behaviour
while (beh->done() == false) {
std::unique_lock<std::mutex> lck(mtxInterThred);
while (!runingThred)
cvInterThred.wait(lck); // bloqué si suspendu ou en attente
lck.unlock();
beh->action();
}
Un doSuspend() met runingThred = false et notifie la condition :
tous les behaviours se bloquent à la prochaine itération.
Un doActivate() ou doWake() remet runingThred = true et
les débloques simultanément.
Signaux RT et concurrence
Les signaux temps-réel POSIX (SIGRTMIN+2 à SIGRTMIN+7) sont
interceptés dans un thread dédié (listener_extern_signals_Thread)
via boost::asio::signal_set. Cela garantit qu’ils ne perturbent
pas les threads de behaviour en pleine exécution.
Avertissement
doDelete() appelé localement (depuis le processus de l’agent
lui-même) appelle _exit(0) directement, sans envoyer de signal.
Ceci évite une boucle infinie : s’envoyer SIGTERM déclencherait
le handler de signal qui enverrait SIGTERM à tout le groupe de
processus.
Enregistrement FIPA
Depuis la version 0.9, l’enregistrement auprès de la plateforme est
automatique si agentplatform est lancé. Il suffit de démarrer le
daemon avant les agents :
# Terminal 1 — lancer la plateforme
./agentplatform
# Terminal 2 — lancer ton application
./my_agent_app
Si la plateforme n’est pas disponible, les agents fonctionnent en
mode dégradé : les behaviours s’exécutent normalement, mais
agentStatus reste AGENT_INITED et les fonctions de découverte
(lookup, search DF) ne sont pas disponibles.
Pour vérifier l’état de la plateforme en cours d’exécution :
# Dans le terminal de agentplatform, taper :
dump
# Résultat exemple :
# [AMS] registre (2 agents) :
# alice pid=4521 addr=ipc:///tmp/acl_alice état=active
# bob pid=4522 addr=ipc:///tmp/acl_bob état=active
# [DF] annuaire (1 service(s)) :
# my-planner type=planning agent=alice ontologie=logistics