OVH Cloud OVH Cloud

Questions à propos de setjmp/longjmp

4 réponses
Avatar
thomas.baruchel
Je crosse-poste sur fr.comp.os.unix et fr.comp.lang.c (avec fu2 *.unix),
non pas pour polluer ces deux groupes, mais après un choix mûrement réfléchi.
Je pense sincèrement ne gêner aucun de ces deux groupes. Ma question
est à l'origine une question de C pur, mais le programme n'étant destiné
à être implémenté que sur des systèmes unix, il se pourrait que des
spécialistes d'unix puisse répondre précisément. Inversement, la fin de
ce message revient à du C pur et je supplie les lecteurs de fr.comp.lang.c
de le lire jusqu'au bout.

J'implémente un code destiné à être "hacké" par les utilisateurs;
je m'explique: des routines de bas niveau sont mises en place, et
l'utilisateur peut avant (re)compilation ajouter ses propres
fonctions (lesquelles seront par ailleurs transmises à un plus haut
niveau à un shell Scheme par libguile).

A peu de choses près, le schéma des fonctions ajoutées est le suivant:
un couple de func0() et func(). La seconde, principale, contient
dans les cas les plus simples uniquement:
return(parser(func0,arg));
(où en fait arg est un pointeur casté par (void *) qui peut pointer
vers n'importe quoi).

Ma fonction parser() lit simplement une base de données du début à la
fin (je rassure les lecteurs: elle est en ramdisk...), et à chaque item
lance: func0(item,arg) à peu de choses près.
Donc l'utilisateur reprend la main, traite les informations, éventuellement
par le biais du pointeur arg peut même transmettre des informations de
sortie à func(), etc.

Vous l'avez compris, l'usage principal ne consiste pas à chercher UN élément
dans la base, mais à parcourir toute la base pour évaluer des ressemblances.

Je suis cependant en train d'écrire la documentation, et envisage la question
suivante: "Peut-on arrêter la recherche en plein milieu?" Cela ne me
dérange absolument pas de répondre NON, dans la mesure où ce n'est pas
le but et où cela ne devrait pas correspondre à un vrai besoin, mais
dans un souci d'exhaustivité, j'ai pensé à l'utilisation de
setjmp/longjmp qui permet de faire cela. Voici enfin ma question:
sachant que parser() n'alloue pas de mémoire dynamiquement,
utilisant simplement deux int et deux char[] de taille fixe, mais
que la fonction utilise néanmoins un FILE * avec fopen/fclose
je me demande ce que vaut la solution setjmp/longjmp en terme
de propreté pour le système. Le schéma serait le suivant:

[func] setjmp + appel à parser()
[parser] fopen + appel à func0() (avant le fclose normal)
[func0] longjmp

Je sais parfaitement que des solutions propres pourraient être
envisagées: func0 étant de type void, on pourrait lui faire
retourner un flag de 0 ou 1 en char ou en int, et parser()
examinerait alors la valeur retournée par func0 pour décider de
fermer proprement le fichier, etc. MAIS je ne le ferai pas: la
vitesse étant la priorité majeure du système, je ne multiplierai
pas les tests en fonction de tous les besoins marginaux qu'on
peut toujours imaginer. Encore une fois, je veux simplement
documenter clairement mon programme pour que l'utilisateur
sache à quoi s'en tenir.

je suppose que cette manoeuvre laissera des déchets dans l'état
du système tout le temps d'exécution du programme (pas après?).
Je rappelle désormais que les seuls systèmes envisagés sont de type
Unix. Imaginons néanmoins que l'utilisateur veuille néanmoins le
faire, j'aimerais lui indiquer précisément ce qu'il en est.
Qu'en est-il par ailleurs pour une utilisation INTENSIVE ?

Il se peut cependant qu'en réalité aucun dommage ne résulte:
après tout, longjmp() restaurant partiellement l'état du système
et le fichier ayant été ouvert dans une fonction appelée après
le setjmp(), peut-être le résultat est-il bien plus "propre" que
ce que je supposais plus haut (je rappelle que mon FILE *) est
déclaré localement par parser(). [Les spécialistes du C ironiseront
sur la propreté de la démarche, mais je rappelle qu'il faut envisager
ici un "hack" personnel à partir d'une base elle totalement portable.
Qu'en est-il ?

Cordialement,

--
« nous devons agir comme si la chose qui peut-être ne sera pas devait
être » (Kant, Métaphysique des moeurs, doctrine du droit, II conclusion)

Thomas Baruchel <baruchel@laposte.net>

4 réponses

Avatar
Laurent Wacrenier
Thomas Baruchel écrit:
sachant que parser() n'alloue pas de mémoire dynamiquement,
utilisant simplement deux int et deux char[] de taille fixe, mais
que la fonction utilise néanmoins un FILE * avec fopen/fclose
je me demande ce que vaut la solution setjmp/longjmp en terme
de propreté pour le système. Le schéma serait le suivant:

[func] setjmp + appel à parser()
[parser] fopen + appel à func0() (avant le fclose normal)
[func0] longjmp


Il faut mettre le setjmp à l'interieur de parser :

jmp_buf env;

parser() {
FILE *f = fopen(...);
if (setjmp(&env) == 0) {
while(...) {
func0(...);
}
}
fclose(f);
}

Pour que func0 puisse faire un lonjmp, il faut que env soit globale
(ce qui empêche le multithread et la recursivité). Or je ne vois pas
trop l'interêt de le faire par setjmp : vu qu'il y a une boucle sur le
curseur pour déterminer si on est naturellement à la fin, il suffit de
simuler cette fin en ayant mis ce curseur en variable globale.

Et plutôt que de laisser les fonctions jouer avec longjump ou le
curseur directement, cache tout celà derrière une fonction.

Avatar
Laurent Deniau
Thomas Baruchel wrote:
Je sais parfaitement que des solutions propres pourraient être
envisagées: func0 étant de type void, on pourrait lui faire
retourner un flag de 0 ou 1 en char ou en int, et parser()
examinerait alors la valeur retournée par func0 pour décider de
fermer proprement le fichier, etc. MAIS je ne le ferai pas: la
vitesse étant la priorité majeure du système, je ne multiplierai
pas les tests en fonction de tous les besoins marginaux qu'on
peut toujours imaginer. Encore une fois, je veux simplement
documenter clairement mon programme pour que l'utilisateur
sache à quoi s'en tenir.


C'est pourtant et de loin la meilleure solution: simple, efficace et logique...

Le temps necessaire a un while(!stop && cond) est negligeable par rapport a
while(cond), surtout si tu utilises des fichiers...

Je te conseille de le faire avec un flag et si ca ne te convient pas, cherche
une autre solution en allant du plus simple au plus complique, l'utilisation de
setjmp/longjmp etant probablement l'une des plus compliquees.

J'utilise ce mecanisme de flag dans mes solveurs lorsque l'utilisateur demande
un arret entre deux iterations avant convergence.

a+, ld

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]

Avatar
Pascal Bourguignon
(Thomas Baruchel) writes:
[func] setjmp + appel à parser()
[parser] fopen + appel à func0() (avant le fclose normal)
[func0] longjmp


Ça peut être génant de laisser le fichier ouvert. Si ça doit être
répété, on peut assez vite atteindre la limite.

Peut être pourriez vous fournir une paire de fonctions de traitement
d'exception, ce qui vous permettrait d'attraper l'exception dans
parser pour fermer le fichier.

Voir par exemple, NSDuring de OpenStep/GNUstep, ou une quelconque
autre bibliothèque de gestion d'exception pour C.


--
__Pascal_Bourguignon__
http://www.informatimago.com/
Do not adjust your mind, there is a fault in reality.

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Laurent Deniau wrote:

Thomas Baruchel wrote:
Je sais parfaitement que des solutions propres pourraient être
envisagées: func0 étant de type void, on pourrait lui faire
retourner un flag de 0 ou 1 en char ou en int, et parser()
examinerait alors la valeur retournée par func0 pour décider de
fermer proprement le fichier, etc. MAIS je ne le ferai pas: la
vitesse étant la priorité majeure du système, je ne multiplierai
pas les tests en fonction de tous les besoins marginaux qu'on
peut toujours imaginer. Encore une fois, je veux simplement
documenter clairement mon programme pour que l'utilisateur
sache à quoi s'en tenir.


C'est pourtant et de loin la meilleure solution: simple, efficace et
logique...


Je suis d'accord. Simplicité et performance assurée.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/