Modèle et exécuteur de tâches asynchrones #36
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ticket #034 — Modèle et exécuteur de tâches asynchrones
Contexte
Labfy Investigation va bientôt exécuter des traitements potentiellement longs :
Ces opérations ne doivent jamais bloquer la boucle principale GTK.
Le ticket #035 ajoutera une file de tâches et un panneau d’activité. Avant cela, il faut créer une abstraction asynchrone fiable, indépendante de GTK et réutilisable par tous les futurs modules.
Objectif
Créer un type opaque :
capable de :
Le module doit s’appuyer sur :
Il ne doit dépendre ni de GTK, ni de SQLite, ni d’une enquête particulière.
Architecture attendue
Créer :
Le flux général doit être :
1. Définir les états publics
Dans :
définir :
Transitions autorisées :
Une tâche terminée ne peut jamais être redémarrée.
2. Définir le type opaque
La structure interne ne doit jamais apparaître dans le header.
3. Définir le worker
Ajouter :
Contrat :
Le worker s’exécute dans un thread secondaire.
Il ne doit jamais :
Le worker peut appeler :
depuis son thread.
4. Définir le callback final
Ajouter :
Le callback doit être appelé après la mise à jour de l’état final.
Lorsqu’une tâche est lancée depuis le thread principal GTK, le callback doit revenir sur ce contexte principal grâce au comportement de
GTask.5. Définir le domaine d’erreur
Ajouter :
Puis :
Utilisation :
FALSEsans fournir deGError;TRUEtout en fournissant une erreur.6. API publique attendue
Construction et références
background_task_new()doit refuser :La tâche utilise un comptage de références atomique.
Ne pas exposer une fonction
background_task_free().Cette décision est importante : la tâche doit pouvoir rester vivante pendant l’exécution même si son propriétaire visuel disparaît.
Démarrage
Propriété des paramètres
Si le démarrage réussit :
Les fonctions de destruction correspondantes seront appelées au moment approprié.
Si le démarrage échoue :
Contraintes
La fonction doit :
task;worker;GError;PENDING;GCancellable;RUNNING;g_task_run_in_thread();Annulation
background_task_cancel()exprime une demande.Le worker reste responsable de vérifier régulièrement :
ou :
L’annulation ne doit jamais tuer brutalement un thread.
Progression
Règles :
GMutex;0.0et1.0;RUNNING;status_messageest copié ;status_message == NULLest accepté.Le ticket #035 pourra lire régulièrement ces valeurs pour mettre à jour le panneau d’activité.
Accesseurs
Propriété des valeurs
get_result()ne doit être considéré comme valide qu’après l’état :7. Structure interne recommandée
Dans :
la structure peut contenir :
Les champs mutables doivent être protégés par
mutex.Le titre est immuable après construction.
8. Contexte interne d’exécution
Créer une structure privée, par exemple :
Le
worker_datadoit être détruit lorsque le contexteGTaskest libéré.Le pointeur
taskpeut être non propriétaire si une référence interne distincte garantit sa durée de vie jusqu’au callback final.9. Fonction exécutée dans le thread
Créer un trampoline privé compatible avec :
Il doit :
g_task_return_pointer();g_task_return_error();BACKGROUND_TASK_ERROR_WORKER_PROTOCOLsi le worker viole son contrat.Cas à traiter :
Si un résultat a été produit alors que l’exécution échoue, il doit être détruit avec
result_destroy.10. Callback interne de fin
Créer un callback privé compatible avec :
Il doit :
g_task_propagate_pointer();1.0en cas de succès ;Détermination de l’état :
Le callback utilisateur doit observer un objet déjà entièrement finalisé.
11. Destruction de la tâche
Quand la dernière référence est libérée :
resultavecresult_destroy;error;GCancellable;GMutex;L’appel suivant doit être accepté :
12. Sécurité des threads
Les opérations suivantes doivent utiliser
GMutex:Ne jamais conserver le mutex verrouillé pendant :
13. Tests unitaires
Créer :
Les tests doivent utiliser un
GMainLooppour attendre le callback final.Test de construction
Vérifier :
Vérifier qu’une tâche valide commence avec :
Test de succès
Créer un worker qui :
TRUE.Vérifier dans le callback :
Vérifier que
result_destroyest appelé lors du dernierunref.Test d’échec
Créer un worker qui retourne :
avec une erreur :
Vérifier :
Test de protocole invalide
Créer un worker qui retourne :
sans renseigner
GError.Vérifier :
Test d’annulation
Créer un worker qui travaille par petites étapes et vérifie régulièrement le
GCancellable.Programmer :
depuis le contexte principal avec
g_timeout_add().Vérifier :
Test de double démarrage
Démarrer une tâche puis rappeler immédiatement :
Vérifier :
La première exécution doit continuer normalement.
Test des données utilisateur
Vérifier que :
worker_data_destroyest appelé exactement une fois ;completion_data_destroyest appelé exactement une fois ;background_task_start()échoue avant transfert de propriété.Test du comptage de références
Démarrer une tâche puis libérer immédiatement la référence de l’appelant.
Vérifier que :
14. Makefile
Le code de production est déjà découvert automatiquement si le Makefile utilise :
Ajouter toutefois une cible de test dédiée :
La cible doit compiler au minimum :
Lier avec les paquets GLib/GIO déjà utilisés par le projet.
Ajouter le binaire aux cibles :
Sortie attendue :
15. Hors périmètre
Ce ticket ne doit pas encore ajouter :
Ces fonctions viendront dans les tickets suivants.
16. Critères d’acceptation
BackgroundTaskest opaque.GTask.GCancellable.GMutex.0.0et1.0.makeréussit.make testréussit.git diff --checkne retourne aucune erreur.17. Audit attendu
Vérifier l’absence de GTK et SQLite :
Résultat attendu :
Vérifier les primitives asynchrones :
Vérifier qu’aucun thread POSIX brut n’est ajouté :
Résultat attendu :
Vérifier l’absence de sortie forcée :
Résultat attendu :
18. Fichiers concernés
Aucune modification de
Applicationou de GTK n’est attendue.19. Commit attendu
Résultat attendu
Après ce ticket, Labfy disposera d’une primitive générique pour exécuter proprement les futurs traitements longs :
Le ticket #035 pourra ensuite construire une file de tâches et un panneau d’activité au-dessus de cette abstraction.