Verwendung von kill in einem subprocess

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
helu1020
User
Beiträge: 12
Registriert: Montag 4. August 2014, 19:38

Hallo Python-Community,
in meinem Python Script rufe ich mittels subprocess durch den Bildbetrachter feh ein fullscreen Bild auf. Ändert sich der String TempFeld, wird ein neues, anderes Bild aufgerufen. Dies funktioniert auch. Jedoch habe ich das Problem, dass das alte Bild, samt Bildbetrachter im Hintergrund weiterhin geöffnet bleibt.
Mittels nachfolgendem Code habe ich versucht durch abfragen der entsprechenden ProcessID und einem subprocess "kill ProcessID" das Bild im Hintergrund zu schließen, was jedoch nicht funktioniert.

Code: Alles auswählen

  TempFeld = str(chr(Xtempfeld))+str(Ytempfeld)
  cmd_open = "feh -x /home/pi/Bilder/" + TempFeld + ".jpg"
  if OldTempFeld != TempFeld:
      if CloseCount !=0:
        OldPID = PID
      ImageProc = subprocess.Popen(cmd_open, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)
      PID = ImageProc.pid
      if CloseCount !=0:
          cmd_close = 'kill ' + str(OldPID)
          #print (cmd_close)
          ImageCloseProc = subprocess.Popen(cmd_close, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)
      OldTempFeld = TempFeld
      CloseCount = CloseCount + 1
Seltsam ist hierbei, dass der (hier auskommentierte) print Befehl funktioniert, der danach folgende subprocess "kill XXXX" aber nicht.

Ich habe es auch schon mit

Code: Alles auswählen

ImageProc.kill()
versucht, was auch nicht funktioniert hat.

Es wäre echt super, wenn mir hier jemand weiter helfen könnte.

Gruß helu1020
BlackJack

@helu1020: Definiere mal „funktioniert nicht”. Solange Du zum Beispiel nicht den Rückgabecode von dem Prozess abrufst, wird der im Zombie-Zustand bleiben.

Warum immer `shell=True`? Ich sehe nicht warum das Sinn machen sollte hier immer zusätzlich Shells dazwischen zu starten.

Man braucht auch nicht ``kill`` als externes Programm zu starten. Selbst wenn `Popen`-Objekte keine `kill()`-Methode hätten, gäbe es die `os.kill()`-Funktion.

Optionale Argumente die man nicht wirklich verwendet braucht man auch nicht alle anzugeben. Deswegen sind die ja optional, damit man sie weg lassen kann wenn man mit dem Default-Wert zufrieden ist.

Ist `CloseCount` tatsächlich nur dazu da damit man beim ersten Bildanzeigeprozess den nicht vorhandenen Vorherigen nicht killt? Das wäre unnötig indirekt. Man könnte dafür `ImageProc` initial einfach an `None` binden und *das* prüfen.

Zum Verbinden von Pfadelementen gibt es `os.path.join()` und um Werte in Zeichenketten zu formatieren verwendet man die `format()`-Methode auf Zeichenketten. `str()` und ``+`` ist eher BASIC, denn Python.

Die Namensschreibweisen halten sich so gar nicht an die Konventionen. → Style Guide for Python Code
BlackJack

@helu1020: Es macht übrigens keinen Sinn das Ergebnis eines `chr()`-Aufrufs an `str()` zu übergeben.

Code: Alles auswählen

import os
from subprocess import Popen

IMAGE_PATH = '/home/pi/Bilder'


# ...

    x_tempfeld = 42
    y_tempfeld = 23
    old_temp_feld = None
    display_process = None

    temp_feld = '{0}{1}'.format(chr(x_tempfeld), y_tempfeld)
    if old_temp_feld != temp_feld:
        if display_process:
            display_process.kill()
            display_process.wait()
        display_process = Popen(
            ['feh', '-x', os.path.join(IMAGE_PATH, temp_feld + '.jpg')]
        )
        old_temp_feld = temp_feld
helu1020
User
Beiträge: 12
Registriert: Montag 4. August 2014, 19:38

@BlackJack: Zunächst vielen Dank für die schnelle Antwort und den wesentlich schöneren Code. Das ist mein erstes Projekt mit Python, daher ist mein Programmierstil leider auch noch entsprechend.

Jedoch wird bei deinem Code Beispiel zuerst das vorherige Bild geschlossen und dann das neue geöffnet, was zu einem nicht schönen (und in meinem Fall inakzeptablen) Bildübergang führt (bei jedem Bildwechsel sieht man kurzzeitig das Terminal). In der Reihenfolge "zuerst schließen des Alten Bildes, dann öffnen des neuen Bildes" hatte es bei mir auch schon funktioniert (nur war mein Code nicht so sauber).
Was eben nicht funktioniert ist, dass zuerst das neue Bild geöffnet wird und dann im Hintergrund das alte Bild geschlossen wird. Bzw. das Öffnen des neuen Bildes funktioniert noch und es entsteht auch der gewünschte sauberer Bildübergang, aber das Schließen des alten Bildes im Hintergrund klappt nicht, es bleibt einfach geöffnet.

Da eben zuerst das neue Bild geöffnet und dann im Hintergrund das alte Bild geschlossen werden soll, habe ich in meinem Code die PID abgefragt und vor dem neuen Bildaufruf auf OldPID umgespeichert um dann, nach dem neuen Bildaufruf, das alte Bild zu schließen.

Wenn du mir nochmals mit einem entsprechendem Code Beispiel helfen könntest, wäre das echt super.

Vielen Dank nochmal für die tolle Antwort.

Gruß helu1020
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@helu1020: hast Du Probleme, zwei Befehle in einer anderen Reihenfolge auszuführen?

Code: Alles auswählen

        old_display_process = display_process
        display_process = Popen(
            ['feh', '-x', os.path.join(IMAGE_PATH, temp_feld + '.jpg')]
        )
        if old_display_process:
            # eventuell noch ein time.sleep(0.3)
            old_display_process.kill()
            old_display_process.wait()
helu1020
User
Beiträge: 12
Registriert: Montag 4. August 2014, 19:38

@Sirius3: Vielen Dank, jetzt funktioniert es genau so, wie es sein soll. Nur anstatt time.sleep(0.3) habe ich time.sleep(0.5) verwenden müssen.
Antworten