0
import tkinter as tk
import tkinter.font
import threading 

def sensor_4():
    i = 0
    while True: 
         i+=1

t4 = threading.Thread(target=sensor_4)

mainwindow = tk.Tk()

HEIGHT = 700
WIDTH = 800

canvas = tk.Canvas(mainwindow, height = HEIGHT, width = WIDTH)
canvas.pack()

frame = tk.Frame(mainwindow, bg='#08030D')  #inside box
frame.place(relx=0, rely=0.1, relwidth = 0.95, relheight = 0.6)

start_sensor4=tk.Button(frame, text = "Press to Start 4", bg='#292230',fg='white',command = t4.start)
start_sensor4.place(relx=0, rely=0.24, relwidth = 0.2, relheight = 0.05)

mainwindow.mainloop()

In the code example, I am able to start the thread function by pressing the button within the Tkinter GUI. I am wondering how I can exit the thread function without the function having to return, and restart the thread by clicking on the same button or maybe a separate button. I also get the error stating that Threads can only be started once, if I click on the start button.

Alan Cai
  • 21
  • 6
  • Does this answer your question? [terminate an Thread controlled](https://stackoverflow.com/a/43686996/7414759) – stovfl Jun 21 '20 at 07:57
  • Consider [threads can only be started once](https://stackoverflow.com/a/54405046/7414759) or [run and kill a thread on a button press](https://stackoverflow.com/a/57678641/7414759) – stovfl Jun 21 '20 at 08:04
  • Those pages did not help me too much, but thanks anyways for them. – Alan Cai Jun 21 '20 at 16:57

2 Answers2

1

The tricky part is here: "without the function having to return". This means that a vanilla thread.join() call will just hang as there is no end to the work the thread must do. We must use the threading.Event() class to achieve a result like this:

def sensor_4(running_event):
    i = 0
    while running_event.is_set():
         i+=1

def manage_thread(thread, running_event):
    if thread.is_alive():
        running_event.clear()
        thread.join()
    else:
        running_event.set()
        thread.start()

running_event = threading.Event()
t4 = threading.Thread(target=sensor_4, args=(running_event,))
..
..
start_sensor4=tk.Button(frame, text = "Press to Start 4", bg='#292230',fg='white',command = lambda: manage_thread(t4, running_event))
..

This does not address the problem of starting the thread more than once but only of starting and stopping using the button without the function having to return. To restart the thread (as in thread.start()) you must make a new thread with the same parameters.

Tresdon
  • 1,211
  • 8
  • 18
  • Thanks, that was helpful. I can confused what you mean I have to make a new thread with the same parameters? Like create a separate button( so 2 buttons instead of one) to start that same thread again? – Alan Cai Jun 21 '20 at 17:00
  • Also is it possible to create a separate button to end the current thread through returning it, and restarting it by using the original button? – Alan Cai Jun 21 '20 at 17:04
  • You won't need a separate button persay but rather some type of thread generation function which returns `threading.Thread(target=sensor_4, args=(running_event,))`. Then you will need to call this thread generation method if your thread was previously stopped and you wanted to start it again – Tresdon Jun 21 '20 at 17:17
  • Check out the question over at https://stackoverflow.com/questions/29692250/restarting-a-thread-in-python to learn a bit more about restarting a thread. The short of it is that you can only call `.start()` one time per `threading.Thread()` object so you would need to create a new object to start the thread with the same work. It might be worth asking yourself why you want to do this as it's not a simple thing to do for the reason that it kinda goes against the idea of what a thread is meant to do (finish some work and eventually join back to the main process) – Tresdon Jun 21 '20 at 17:21
  • 1
    Thanks, I might look into a different approach instead of trying to stop and restart the thread. – Alan Cai Jun 21 '20 at 17:28
1

I think the "answer" greatly depends on how you define your design problem you are trying to solve and then how you ask the question.

The answers seem to key off of your question related to stopping and restarting the thread.

Reading "between the lines" for what you are trying to accomplish is different.

I think, based on your code, that your design issue is to PAUSE the thread, which is far different from stopping and restarting.

@Tresdon gives ref to discussion about threads and exceptions. When in the exception, the thread is not yet dead, unless it is unhandled. The ref'd discussion points out that threads have resources allocated, and once killed (deallocated) it is not a restart but a new creation that is required.

To PAUSE the thread, you simply need a flag that can be read in the thread code, and toggled by your main code. If set, the thread can "wait", if not set the thread code runs. Depending on other design criteria, the wait piece can be a sleep, or some other pausing mech that may consume more or less resources.

Otto Hirr
  • 21
  • 5