Frage

Ich arbeite an einer GUI-Anwendung in WxPython, und ich bin nicht sicher, wie ich sicherstellen kann, dass nur eine Kopie der meine Anwendung ausgeführt wird, jederzeit auf die Maschine.Aufgrund der Art der Anwendung, ausführen mehr als einmal macht keinen Sinn, und scheitert schnell.Unter Win32, ich kann einfach machen, einen benannten mutex und überprüfen Sie, dass beim Start.Leider weiß ich nicht von jedem Einrichtungen in Linux, die dies tun können.

Ich bin auf der Suche nach etwas, dass wird automatisch freigegeben werden, sollte die Anwendung Abstürzen, unerwartet.Ich möchte nicht haben, um Belastung meinem Benutzern mit, dass Sie manuell löschen, lock-Dateien, weil ich gestürzt bin.

War es hilfreich?

Lösung

Es gibt verschiedene Techniken, einschließlich der Verwendung von Semaphoren. Der, den ich am häufigsten verwendet sehen, ist eine „pid Sperrdatei“ beim Start zu erstellen, die pid des laufenden Prozesses enthält. Wenn die Datei bereits vorhanden ist, wenn das Programm startet, öffnen Sie es und die pid greift nach innen, um zu sehen, ob ein Prozess mit dem pid ausgeführt wird, wenn er den cmdline Wert in / proc / ist zu überprüfen pid zu sehen, ob es sich um eine Instanz des Programms ist es, wenn es dann verlassen wird, da sonst die Datei mit der pid überschreiben. Der üblicher Name für die pid-Datei application_name .pid.

Andere Tipps

Das Richtige ist beratende Sperrungen mit flock(LOCK_EX); in Python, wird dies in der fcntl Modul .

Im Gegensatz zu Pidfile werden diese Sperren immer automatisch freigegeben, wenn der Prozess stirbt aus irgendeinem Grunde hat keine Rennbedingungen Löschung Datei existieren beziehen (wie die Datei nicht Notwendigkeit gelöscht wird die freizugeben sperren), und es gibt keine Möglichkeit, einen anderen Prozess die PID vererben und somit erscheint eine veraltete Sperre zu überprüfen.

Wenn Sie unsauber Shutdown Erkennung möchten, können Sie einen Marker (wie Ihre PID, für Traditionalisten) in die Datei nach sich ziehen das Schloss, schreiben und dann die Länge der Datei auf 0-Byte-Status vor einem sauberen Shutdown (während das Schloss wird gehalten); also wenn die Sperre nicht gehalten wird und die Datei nicht leer ist, ein unreines Abschaltung angezeigt wird.

Komplette Schließlösung mit dem fcntl Modul:

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)

wxWidgets bietet eine wxSingleInstanceChecker Klasse für diesen Zweck: WxPython doc oder wxWidgets doc . Die wxWidgets doc Beispielcode in C ++, aber der Python äquivalent sollte in etwa so (ungetestet) sein:

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

Diese baut auf den Antwort von Benutzer zgoda.Es geht vor allem eine heikle Anliegen zu tun, mit Schreibzugriff auf die lock-Datei.Insbesondere, wenn die lock-Datei ursprünglich erstellt wurde, indem root, ein weiterer Benutzer foo kann dann nicht erfolgreich mehr Versuch, zu schreiben, diese Datei wegen fehlender Schreibrechte für Benutzer foo.Die offensichtliche Lösung scheint es zu sein, erstellen Sie die Datei mit write-Berechtigungen für alle.Auch diese Lösung baut auf einem anderen Antwort von mir, zu tun, erstellen Sie eine Datei mit einem solchen benutzerdefinierte Berechtigungen.Dieses Anliegen ist wichtig in der realen Welt, wo das Programm ausgeführt werden kann von jedem Benutzer einschließlich root.

import fcntl, os, stat, tempfile

app_name = 'myapp'  # <-- Customize this value

# Establish lock file settings
lf_name = '.{}.lock'.format(app_name)
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
# Regarding umask, see https://stackoverflow.com/a/15015748/832230
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: {} may already be running. Only one instance of it '
           'can run at a time.'
           ).format('appname')
    exit(msg)

Eine Beschränkung der dem obigen code ist, dass, wenn die lock-Datei schon mit unerwarteten Berechtigungen, die Berechtigungen werden nicht korrigiert.

Ich hätte gerne verwenden /var/run/<appname>/ als Verzeichnis für die lock-Datei, sondern erstellen Sie dieses Verzeichnis benötigt root Berechtigungen.Können Sie machen Sie Ihre eigene Entscheidung für das Verzeichnis zu verwenden.

Beachten Sie, dass es ist keine Notwendigkeit zu öffnen ein Datei-handle, das der lock-Datei.

Hier ist die TCP-Port-basierte Lösung:

# Use a listening socket as a mutex against multiple invocations
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 5080))
s.listen(1)

Geben Sie für ein Python-Modul, das auf Unix-Schnittstellen zu SYSV Semaphore. Die Semaphore haben eine SEM_UNDO Flagge, die die Ressourcen durch den Prozess gehalten werden dazu führen, wenn zum Absturz des Prozesses freigegeben werden.

Ansonsten wie Bernard vorgeschlagen, können Sie

import os
os.getpid()

Und schreiben Sie es auf /var/run/application_name.pid. Wenn der Prozess startet, sollte es prüfen, ob die pid in /var/run/application_name.pid in der ps Tabelle aufgeführt ist, und beenden, wenn es sonst seine eigene pid schreiben in / var / run / application_name .pid. Im folgenden var_run_pid ist die pid Sie lesen von / var / run / application_name .pid

cmd = "ps -p %s -o comm=" % var_run_pid
app_name = os.popen(cmd).read().strip()
if len(app_name) > 0:
    Already running

Die Gesamtheit der Funktionen in semaphore.h definiert - sem_open(), sem_trywait(), usw. - sind die POSIX-Äquivalent, glaube ich

.

Wenn Sie eine Sperrdatei erstellen und die pid darin setzen, können Sie Ihren Prozess-ID dagegen überprüfen und feststellen, ob Sie abgestürzt, nicht wahr?

Ich habe nicht persönlich getan, so nehmen Sie mit geeigneten Mengen an Salz. : P

Sie können das 'pidof' Utility? Wenn Ihr App läuft, wird pidof den Prozess-ID des App auf stdout schreiben. Wenn nicht, wird es eine neue Zeile gedruckt (LF) und zurück einen Fehlercode.

Beispiel (von bash, der Einfachheit halber):

linux# pidof myapp
8947
linux# pidof nonexistent_app

linux#

Bei weitem die am häufigsten verwendete Methode ist eine Datei in / var fallen / run / genannt [Anwendung] .pid, die nur die PID des laufenden Prozesses enthält, oder übergeordneten Prozess. Als Alternative können Sie eine Named Pipe im gleichen Verzeichnis erstellen, um Nachrichten in dem aktiven Prozess zu senden, z.B. eine neue Datei zu öffnen.

Ich habe für den Betrieb dieser Art von Anwendungen, die ein Grundgerüst aus, wenn Sie in der Lage sein wollen, die Befehlszeilenargumente der nachfolgenden versucht Instanzen der ersten zu übergeben. Eine Instanz startet auf einem vordefinierten Port lauscht, wenn es schon da hört keine Instanz finden. Wenn eine Instanz bereits vorhanden ist, sendet er seine Befehlszeilenargumente über die Socket und beendet das Programm.

Code w / Erklärung

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top