28 votes

Assurer une seule instance d'une application sous Linux

Je suis en train de travailler sur une application graphique en WxPython, et je ne suis pas sûr de savoir comment je peux assurer qu'une seule copie de ma demande est en cours d'exécution à un moment donné sur la machine. En raison de la nature de l'application, l'exécution de plus d'une fois, n'a aucun sens, et échouera rapidement. Sous Win32, je peux tout simplement faire un mutex nommé et vérifier au démarrage. Malheureusement, je ne sais pas de toutes les installations de Linux qui peut faire cela.

Je suis à la recherche de quelque chose qui sort automatiquement si le plantage de l'application de façon inattendue. Je ne veux pas avoir à charge à mes utilisateurs d'avoir à supprimer manuellement les fichiers de verrouillage car j'ai chuté.

49voto

Charles Duffy Points 34134

La bonne Chose est consultatif de verrouillage à l'aide d' flock(LOCK_EX); en Python, cela se trouve dans l' fcntl module.

Contrairement à pidfiles, ces serrures sont toujours automatiquement libéré lors de votre processus meurt pour une raison quelconque, n'ont pas de course il existe des conditions relatives à la suppression du fichier (le fichier n'a pas besoin d'être supprimés afin de libérer le verrou), et il n'y a aucune chance de différents processus d'hériter de la PID et apparaissant ainsi de valider un état de verrouillage.

Si vous voulez impur de l'arrêt de la détection, vous pouvez écrire un marqueur (comme votre PID, pour les traditionalistes) dans le fichier après l'accaparement de la serrure, puis tronquer le fichier de 0 octet de statut avant un arrêt propre (tant que le verrouillage est en cours); ainsi, si la serrure n'est pas tenue et que le fichier n'est pas vide, impure, l'arrêt est indiqué.

21voto

Robert Gamble Points 41984

Il existe plusieurs techniques, y compris à l'aide de sémaphores. Celui que je vois le plus souvent utilisé est de créer un "pid fichier de verrouillage" au démarrage qui contient le pid du processus en cours d'exécution. Si le fichier existe déjà lorsque le programme démarre, l'ouvrir et de saisir le pid à l'intérieur, vérifiez pour voir si un processus qui pid est en cours d'exécution, si elle est de vérifier l'cmdline valeur dans /proc/pid pour voir si c'est une instance de votre programme, si c'est pour le quitter, sinon remplacer le fichier avec votre pid. L'habitude nom pour le fichier pid est *application_name*.pid.

18voto

zgoda Points 8549

Solution de verrouillage complète utilisant le module fcntl :

 import fcntl
pid_file = 'program.pid'
fp = open(pid_file, 'w')
try:
    fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    # another instance is running
    sys.exit(1)
 

8voto

Brian Victor Points 128

wxWidgets propose une classe wxSingleInstanceChecker à cet effet: wxPython doc ou wxWidgets doc . Le document wxWidgets contient un exemple de code en C ++, mais l'équivalent python devrait ressembler à ceci (non testé):

   name = "MyApp-%s" % wx.GetUserId()
  checker = wx.SingleInstanceChecker(name)
  if checker.IsAnotherRunning():
      return False
 

4voto

A-B-B Points 797

Elle se base sur la réponse par l'utilisateur zgoda. Il traite essentiellement d'une question délicate souci d'avoir à faire avec l'accès en écriture au fichier de verrouillage. En particulier, si le fichier de verrouillage a été créé par root, un autre utilisateur foo pouvez ensuite pas réussi à plus la tentative de réécrire ce fichier en raison de l'absence des autorisations d'écriture pour l'utilisateur foo. La solution la plus évidente semble être de créer un fichier avec les permissions d'écriture pour tout le monde. Cette solution s'appuie également sur une autre réponse par moi-même, d'avoir à faire la création d'un fichier avec de telles autorisations personnalisées. Cette préoccupation est importante dans le monde réel où votre programme peut être exécuté par n'importe quel utilisateur.

import fcntl, os, stat, tempfile

# Establish lock file settings
lf_name = '.appname.lock'
lf_path = os.path.join(tempfile.gettempdir(), lf_name)
lf_flags = os.O_WRONLY | os.O_CREAT
lf_mode = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH  # This is 0o222, i.e. 146

# Create lock file
umask_original = os.umask(0)
try:
    lf_fd = os.open(lf_path, lf_flags, lf_mode)
finally:
    os.umask(umask_original)

# Try locking the file
try:
    fcntl.lockf(lf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    msg = ('Error: {0} may already be running. Only one instance of it '
           'can run at a time.'
           ).format('appname')
    exit(msg)

J'aurais bien aimé utiliser /var/run/<appname>/ que le répertoire pour le fichier de verrouillage, mais la création de ce répertoire exige root des autorisations. Vous pouvez faire votre propre décision pour un répertoire à utiliser.

Notez qu'il n'est pas nécessaire d'ouvrir un handle de fichier pour le fichier de verrouillage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X