Être sûr qu'un programme ne sera lancé qu'une fois à la fois

Bonjour tout le monde,

Pour des raisons propres à mon application, je voudrais être certains que celle-ci ne soit lancée qu’une et une seule fois.

A ce jour, j’ai un traitement en bash qui teste sa présence dans le retour de la commande ps et qui crée un fichier verrou dans /tmp au lancement de l’application (on ne peut lancer l’application que si le fichier de verrou est absent).

Enfin bref, le traitement est un peu compliqué et n’est pas encore parfais alors je voudrais savoir s’il existe une commande standard pour ce genre de problématique ?

Salut,
si ton programme doit ce lancer au démarrage, il y a “start-stop-daemon” avec l’option “–make-pidfile” qui permet de gérer ça.

Merci Willy.P pour ta réponse.

Ce n’est malheureusement pas le cas. Mon programme doit être lancé après avoir exécuté un batch (dans lequel je peux mettre en place n’importe quel mécanisme par contre).

un batch de pré-lancement?
nano /usr/local/bin/mon_batch_pre

#!/bin/bash
if [ “$(ps -A | grep le_nom_du_prgz)” == “” ];
then le_nom_progz
else echo “programme est déjà en cours d’exécution PID:”$(ps -A | grep le_nom_du_prgz)
fi

et si tu est en Xorg tu ajoute

else echo | Xdialog --textbox “programme est déjà en cours d’exécution PID:$(ps -A | grep le_nom_du_prgz)” 0 0

Xdialog ou Zenity

Salut,

Certains ont résolu le problème avec un fichier “lock” créé par le script de lancement et <ton_prog>&&

Merci pour ton script dchost99. J’ai déjà mis en place quelque chose du genre, un peu plus étoffé même mais si vous lancez deux fois d’affilé le script : vous n’êtes pas à l’abri de lancer deux fois le programme (car le fichier de lock n’est pas encore créé par le premier lancement au moment où le deuxième teste l’existence du fichier).

L’algorithme était en effet déjà un tout petit peu long (test de la commande ps, test du fichier lock, écriture dans des logs et compagnie) donc j’ai dédoublé mon test sur le fichier de lock, juste à la dernière seconde. Cela marche infiniment mieux mais une fois par moi, inévitablement, un double lancement du script entraîne effectivement deux lancement de l’application à cause d’une “inversion” (le deuxième lancé double le premier 0_o).

J’ai conscience que ce n’est pas simple de comprendre sans avoir le script sous les yeux mais je ne suis malheureusement pas autorisé à le montrer. Je ne cherche cependant pas de l’aide sur sa réalisation, je cherche simplement une autre idée d’algorithme ou une commande système magique pour ce genre de chose.

Que veux-tu dire par <mon_prog>&& ggoodluck47 ? Je ne connais pas la syntaxe “&&” à part pour un ET logique et j’ai du mal à trouver ça en recherchant sur Internet :slight_smile:

prg1 && prg2
prg2 sera exécuté seulement si la commande prg1 s’est déroulé avec succès.
J’avais pas compris qu’il te fallait autant de réactivité.

Merci pour vos réponses, je vais essayer de raccourcir le script pour qu’il soit plus réactif.

Faire uniquement :

test -f /tmp/lock && exit
touch /tmp/lock && mon_prog

(ou du genre) me paraît un peu court pour mes besoins mais y’a sûrement des choses à améliorer. Merci encore.

[quote=“Phi”]test -f /tmp/lock && exit
touch /tmp/lock && mon_prog[/quote]
Il y a toujours une fenêtre de temps (très courte) entre le test et la création du fichier, durant laquelle il peut y avoir une « race condition » (désolé, j’ai aucune idée de la traduction française s’il y en a seulement une).

Ce qu’il faut, c’est que la fonction du kernel appelée par la commande fasse le test et la création atomiquement (ou, dit autrement, que la fonction de création renvoie une erreur si l’objet créé existe déjà).
Deux fonctions me viennent à l’esprit, dont la sémantique est reprise à la lettre dans les commandes équivalentes : mkdir et mkfifo.
Voir les pages man correspondantes mkdir(2) et mkfifo(3), et celles des commandes homonymes mkdir(1) et mkfifo(1).

[code]mkdir /tmp/.répertoire-lock 2> /dev/null && { le-programme; rmdir /tmp/.répertoire-lock; }

ou bien

mkfifo /tmp/.fifo-lock 2> /dev/null && { le-programme; rm /tmp/.fifo-lock; }[/code]

Désolé pour les accolades { } il y a sûrement moyen de s’en passer mais quel que soit le langage je ne suis jamais sûr de la précédence des opérateurs donc je préfère faire en sorte qu’il n’y ait pas d’ambiguïté.

Le ; entre le-programme et le rm(dir) est important, il ne faut pas le remplacer par || ou && ou quoi que ce soit d’autre, c’est ce qui assure que le fifo ou répertoire soit supprimé quel que soit le résultat du programme.

premièrement ton topic tu aurais du le mettre dans la partie programmation
bon sinon moi je te propose un truc bizarre
c’est de ralonger ton script, le ralentir

  1. controle de l’existence du fichier lock
  2. sleep d’un temps aléatoire entre 1 et 5 sec
  3. controle en core l’existence du fichier lock
  4. ecriture du fichier lock si existe pas sinon on quitte

je pense que cela fonctionne

[quote=“bobzer”]bon sinon moi je te propose un truc bizarre
c’est de ralonger ton script, le ralentir

  1. controle de l’existence du fichier lock
  2. sleep d’un temps aléatoire entre 1 et 5 sec
  3. controle en core l’existence du fichier lock
  4. ecriture du fichier lock si existe pas sinon on quitte[/quote]
    Effectivement c’est bizarre… le problème initial (délai entre le test 3 et la création 4) persiste, le contrôle préalable 1 et l’attente 2 n’ont strictement aucun effet dessus.

La seule solution fiable reste d’utiliser une commande garantissant l’atomicité de la création et du test, comme celles que j’ai évoquées précédemment. Il en existe sûrement d’autres que ces deux là, mais par contre je ne les connais pas. Enfin, pour l’utilisation qui en est faite je ne vois pas ce qui empêcherait d’utiliser un répertoire ou un pipe fifo à la place d’un fichier normal…

En C tout serait plus simple : il suffirait d’appeler open("/tmp/.fichier-lock",O_CREAT|O_EXCL), cf. open(2).

bobzer, merci pour ta réponse.

Si mon topic est mal rangé (et il l’est effectivement), je m’en excuse et invite les modérateurs à le déplacer.

Concernant ta solution, elle ne fonctionnera pas (les deux appels hypothétiquement successifs tomberont tous les deux dans le sleep ce qui ne changera rien : j’ai déjà testé ^^).

syam, merci également de participer ! Et pour cause, tu amènes deux solutions qui me paraissent très judicieuses !! Le programme tournant ensuite étant en C, rien ne m’empêche d’y positionner le test : reste à me documenter sur cette syntaxe que je ne connais pas mais je vais m’en sortir, merci ! Pour le lock avec mkdir : très bonne idée :slight_smile: je testerai au pire.

ben l’idée du sleep c’est pour etre sur que si tu lance un deuxieme script il fasse le sleep et donc pendant ce temps l’autre pourra verifier faire le fichier et a la fin du sleep, il vera qu’un autre et deja lancer et donc quitte

Oui mais comme je disais, j’ai déjà testé mais cela n’empêche pas le lancement du programme dans certains cas où les deux appels au batch sont très rapprochés (le deuxième est ralenti mais le premier aussi et finalement, ça ne change pas grand chose).

Salut,

Au lieu de déplacer ce post, je vous propose, lorsqu’une bonne solution aura été trouvée de la faire figurer dans T & A :slightly_smiling:

Effectivement, si tu as déjà un programme en C ça sera beaucoup plus simple de l’inclure dedans, à moins que tu aies besoin du lock pendant les diverses opérations que ton script effectue avant de lancer le programme lui-même.

Sinon, je m’apprêtais à écrire une petite commande pour ça, j’avais même déjà trouvé le nom (vachement original) : mklock.
Par acquit de conscience j’ai tout de même fait une petite recherche sur ce nom et je suis tombé là dessus : geo.unizh.ch/~uruetsch/softw … klock.html
Ça fait exactement ce dont tu as besoin, il faut juste compiler un petit fichier C de 2ko. :wink:

Dommage que personne n’ait pensé à chercher ça avant de se torturer la tête. :mrgreen:

Petite précision importante : la source de cet utilitaire, qui utilise également open(O_CREAT|O_EXCL), indique que O_EXCL ne fonctionne pas correctement sur des partitions NFS. Si tu es dans ce cas de figure, il vaudrait peut-être mieux se rabattre sur la méthode utilisant un répertoire.

Ton lien : :049

J’ai testé en mettant en place un traitement pour créer un verrou et lancer une appli.

Ensuite j’ai simulé des appels successifs très rapprochés en faisant un autre batch similaire à ceci :

mon_premier_batch &
mon_premier_batch &
mon_premier_batch &

Seul le premier passe, les autres sont bloqués :slight_smile: Le verrou est automatiquement supprimé à la fin de “mon_premier_batch” et c’est parfait :wink:

Merci infiniment ! Je choisis ta dernière réponse comme celle ayant résolu mon topic.

Salut,

Nous comptons sur toi, Phi, pour nous mettre cela dans T & A :slightly_smiling: et je pense que nous verrons bientôt une copie dans le wiki :slightly_smiling:

Il y avait un truc qui me travaillait : cette histoire de partitions NFS qui ne supportent pas O_EXCL et sur lesquelles il faut créer un répertoire plutôt qu’un fichier.

J’aurais pu en rester là et me dire qu’en cas de NFS il suffirait de remplacer mklock par un bon vieux mkdir dans le script, mais le fonctionnement d’outils similaires (mktemp en l’occurrence) m’a convaincu qu’il fallait rajouter une option dans la commande elle-même. J’ai également rajouté un peu d’aide (en anglais pour ne pas dépareiller), ça manquait cruellement.

Le tout reste sous GPL bien évidemment.
mklock.c.tar.gz (1.46 KB)
[size=70]Je sais, le code est crade, mais il l’était déjà avant que j’intervienne.[/size] :blush:

Edit : pour ceux qui n’ont pas l’habitude… (il faut au moins le paquet build-essential et probablement aussi les headers du kernel)

[code]$ gcc -o mklock mklock.c && strip --strip-unneeded mklock

cp mklock /usr/local/bin/[/code]

Sinon,en faisant un petite recherche dans packages.debian.org, j’ai trouvé lockfile-progs qui permet de verrouiller des fichiers.

Edit: Le liens, ça peut être utile: packages.debian.org/lenny/lockfile-progs