Seite 1 von 1
Threads um Endlosschleife abzubrechen?
Verfasst: Samstag 6. Juni 2015, 13:31
von semper27
Hallo,
dank der Hilfe hier im Forum habe ich ein Tkinter Programm, dass den print Befehl in einer Endlosschleife ausführt mit einem Button zum Stoppen der Schleife (
http://www.python-forum.de/viewtopic.php?f=18&t=36170). Jetzt möchte ich in der Schleife ein externes Gerät steuern, was einige Minuten dauert und auch währenddessen die Schleife abbrechen können. Sollte ich das mit 2 Threads machen oder gibt es da einen bessere Lösung? Hier
https://gist.github.com/zed/4067619wurde ein ähnliches Problem z.B. mit subprocess gelöst
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Samstag 6. Juni 2015, 16:58
von DasIch
Threads zu nutzen wäre durchaus sinnvoll. Bei der Verwendung von Threads würdest du einen Thread haben indem du mit dem Gerät kommunizierst, diesem Thread würdest du über eine Queue Nachrichten schicken wie z.B. abbrechen und du würdest after bzw. after_idle nutzen um eine Methode im GUI Thread mit einer Nachricht aufzurufen die auf die dann mit Veränderungen an der GUI reagiert werden kann.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 7. Juni 2015, 16:34
von semper27
Danke für deinen Beitrag. Zum testen habe ich mal diesen Thread genommen:
Code: Alles auswählen
class sleepThread(threading.Thread):
def run(self):
i = 1
while True:
print (i)
time.sleep(15)
i = i+1
Das Fenster lässt sich bedienen während die Schleife läuft. Aber leider kriege ich das Abbrechen der Schleife nicht hin. Wenn der Stop Button gedrückt wird sollte sich der Thread beenden, auch wenn er grade time.sleep ausführt. Könnt Ihr mir einen Tipp geben was ich machen muss?
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 7. Juni 2015, 16:43
von Sirius3
@semper27: dazu müssen ja zwei Threads miteinander kommunizieren, dazu gibt es verschiedene Klassen in threading. Für Deinen Fall würde sich "threading.Event" mit seiner wait-Methode anbieten.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 7. Juni 2015, 23:20
von semper27
In der Dokumentation von threading.Event wird beschrieben wie ein Thread wartet bis ein Event auftritt. Ich möchte aber das der Thread beendet wird wenn ein Event auftritt, oder verstehe ich da etwas falsch?
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Montag 8. Juni 2015, 06:17
von Sirius3
@semper27: Du willst doch warten, bis ein Event auftritt, um dann die Schleife zu beenden.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 14. Juni 2015, 14:07
von semper27
Ich habe die Steuerung des Geräts jetzt in viele Einzelschritte zerlegt und vor jedem die Abbruchbedinung geprüft. Danke für die Beiträge.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 14. Juni 2015, 16:08
von Sirius3
@semper27: das hört sich nach keiner guten Idee an.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Samstag 8. August 2015, 11:57
von semper27
Oh, deinen letzten Beitrag hatte ich nicht mehr gelesen. Ist zwar schon eine Weile her und der Programmteil funktioniert auch ganz gut, aber fals noch jemand einen Tipp hat was man es besser programmieren kann würde ich mich freuen. Hier der Code:
Code: Alles auswählen
from functools import partial
import ScrolledText
import serial
import threading
import time
import tkFileDialog
import Tkinter as tk
class ProgrammThread(threading.Thread):
def __init__(self, masetr=None):
threading.Thread.__init__(self)
self.stop_signal = False
def run(self):
k = 0
while True:
if self.stop_signal == False:
#hier wird in jedem Durchlauf ein anderer Befehl ausgeführt
if k == 10: break
k = k+1
main_frame.stop()
class MainFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.start_button = tk.Button(self, text='Skript Starten', relief='flat', command=self.start)
self.start_button.grid(row=0, column=4, sticky='W')
self.stop_button = tk.Button(self, text='Stop', state=tk.DISABLED, relief='flat', command=self.stop)
self.stop_button.grid(row=0, column=5, sticky='W')
def start(self):
self.start_button['state'] = tk.DISABLED
self.stop_button['state'] = tk.NORMAL
self.programm = ProgrammThread()
self.programm.setDaemon(True)
self.programm.start()
def stop(self):
self.start_button['state'] = tk.NORMAL
self.stop_button['state'] = tk.DISABLED
self.programm.stop_signal = True
if __name__ == '__main__':
root = tk.Tk()
main_frame = MainFrame(root)
main_frame.pack()
root.mainloop()
Das beim Drücken von Start noch jedesmal ein neuer Thread erstellt wird wollte ich noch ändern.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Samstag 8. August 2015, 14:00
von Sirius3
@semper27: Zeile 19 wäre ja das Interessante. stop_signal sollte nie etwas anderes sein als False, weil Du sonst eine Endlosschleife hast. So wie es jetzt geschrieben ist, ist es nur eine komplizierte for-Schleife:
Code: Alles auswählen
def run(self):
for k in range(11):
if self.stop_signal:
break
do_something()
Aus Threads heraus darf die GUI nicht verändert werden, Du mußt also innerhalb der GUI per after regelmäßig abfragen, ob der Thread noch läuft; außerdem ist main_frame eine globale Variable, die nicht existieren sollte; die Zeilen in 'if ... __main__' gehören in eine Funktion, die üblicherweise main heißt. Eingerückt wird mit 4 Leerzeichen.
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 9. August 2015, 08:51
von BlackJack
@semper27: `ProgrammThread.__init__` hat ein `masetr`-Argument, das überhaupt nicht verwendet wird.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import Tkinter as tk
from threading import Thread
from time import sleep
class ProgramThread(Thread):
def __init__(self):
Thread.__init__(self)
self.stop_signal = False
def run(self):
for i in xrange(11):
if self.stop_signal:
break
print(i)
sleep(1)
class MainFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.thread = None
self.start_button = tk.Button(
self, text='Skript Starten', command=self.start
)
self.start_button.pack(side=tk.LEFT)
self.stop_button = tk.Button(
self, text='Stop', state=tk.DISABLED, command=self.stop
)
self.stop_button.pack(side=tk.LEFT)
def _check_thread(self):
if self.thread.is_alive():
self.after(500, self._check_thread)
else:
self.start_button['state'] = tk.NORMAL
self.stop_button['state'] = tk.DISABLED
self.thread = None
def start(self):
assert self.thread is None
self.start_button['state'] = tk.DISABLED
self.stop_button['state'] = tk.NORMAL
self.thread = ProgramThread()
self.thread.daemon = True
self.thread.start()
self._check_thread()
def stop(self):
assert self.thread is not None
self.thread.stop_signal = True
def main():
root = tk.Tk()
main_frame = MainFrame(root)
main_frame.pack()
root.mainloop()
if __name__ == '__main__':
main()
Re: Threads um Endlosschleife abzubrechen?
Verfasst: Sonntag 9. August 2015, 13:43
von semper27
Vielen Dank euch beiden für die Tips und den Code! Jetzt verstehe ich Threads mit GUI besser, und das Programm läuft auch flüssig wenn oft Start/Stop gedrückt wird
