Il existe des cas où il faut empêcher un programme d'être lancé 2 fois. Par exemple parce que le programme mobilise du hardware. Ou parce que le programme doit agir de façon unique sur des données. Etc…
Mais comment faire? La solution trouvée doit répondre à 2 conditions:
1- le programme doit “s'apercevoir” qu'une instance précédente est encore active.
2- en cas d'arrêt anormal (plantage), il doit être possible de relancer le programme
La solution proposée ici repose sur le verrouillage d'un fichier. Elle est multiplateforme, mais les instructions ne sont pas identiques pour les différents OS.
Les fonctions de verrouillage se trouvent dans un module appelé, par exemple “verroufichier.py”, et codé comme suit:
#!/usr/bin/python # -*- coding: utf-8 -*- # Python v2.7 import sys ############################################################################# def lockfile_unix(f): """Unix: verrouille le fichier dont le descripteur est f """ lockf(f.fileno(), LOCK_EX | LOCK_NB) ############################################################################# def lockfile_win(f): """Windows: verrouille le fichier dont le descripteur est f """ locking(f.fileno(), LK_NBLCK, 1) ############################################################################# def lockfile_rien(f): """Ni Windows ni Unix: cette fonction ne fait rien """ pass ############################################################################# lockfile = None # si Unix try: from fcntl import lockf, LOCK_NB, LOCK_EX lockfile = lockfile_unix except: pass # si Windows: if lockfile == None: try: from msvcrt import locking, LK_NBLCK, LK_UNLCK lockfile = lockfile_win except: pass # si aucune des 2 importations ne marche: if lockfile == None: lockfile = lockfile_rien
Et voilà un exemple d'utilisation:
#!/usr/bin/python # -*- coding: utf-8 -*- import os, sys import time from verroufichier import lockfile ############################################################################# def bidon(): """programme qui ne fait rien d'autre que d'attendre 15 secondes de CPU""" t0 = time.clock() while True: if time.clock()-t0 > 15: break ############################################################################# if __name__ == '__main__': # tentative de verrou sur le fichier témoin (mettre le bon chemin) nfc = "fichierverrou.txt" f = None try: f = open(nfc, 'w') lockfile(f) except: if f != None: f.close() print u"Echec: il y a déjà une 1ère instance en cours!" sys.exit() bidon() f.close() # le fichier témoin doit rester ouvert jusqu'à la fin du programme
On peut vérifier que le verrou, une fois mis sur le fichier, disparait bien avec l'arrêt du programme, même un arrêt anormal.
Le fichier témoin peut être placé selon le problème à résoudre. Par exemple:
Amusez-vous bien!