Как остановить поток в python

Помогите решить задачу: есть кнопка Play, при нажатии она меняет значение на Stop, и создается поток, в котором происходит цикл. Как сделать так, чтобы при клике по кнопке со значением Stop поток останавливался? А при клике по кнопке со значением Play - начинался?

import tkinter as tk
import threading
import time
import sys

def main():
    if button_1['text'] == 'Play':
        button_1['text'] = 'Stop'
        thread = threading.Thread(target=run)
        thread.start()
    else:
        button_1['text'] = 'Play'
        sys.exit()

def run():
    counter = 1
    while counter <= 5:
        print(counter)
        counter += 1
        time.sleep(0.5)

window = tk.Tk()

button_1 = tk.Button(window, text='Play', command=main)
button_1.pack()

window.mainloop()

Метод sys.exit() не подходит, так как он ждет пока завершится цикл и только потом срабатывает.


Ответы (3 шт):

Автор решения: Никита

Поток остановить невозможно. Но можно передать так называемый сигнал потоку что ему нужно остановиться. Этим сигналом может быть простая глобальная переменная, котороя будет проверяться в цикле while True.

Вот как это может выглядить:

import tkinter as tk
import threading
import time
import sys

def main():
    global thread_stop

    if button_1['text'] == 'Play':
        button_1['text'] = 'Stop'
        thread_stop = False #Что-бы поток не остановился присваеваем False
        thread = threading.Thread(target=run)
        thread.start()
    else:
        button_1['text'] = 'Play'
        thread_stop = True #Присваеваем значение True и завершаем поток

thread_stop = False

def run():
    counter = 1
    while counter <= 5:
        if thread_stop == True: return #Останавливаем цикл
        print(counter)
        counter += 1
        time.sleep(0.5)

window = tk.Tk()

button_1 = tk.Button(window, text='Play', command=main)
button_1.pack()

window.mainloop()

Таким образом при нажати на кнопку "Стоп", вам нужно будет присвоить переменной thread_stop значение True и поток остановиться, а при включении потока присвоить значение False.

→ Ссылка
Автор решения: Yan Wolf

Еще один способ:

import tkinter as tk
import threading
import time
import sys

counter = 1

def main():
    global counter
    if button_1['text'] == 'Play':
        button_1['text'] = 'Stop'
        thread = threading.Thread(target=run)
        thread.start()
    else:
        button_1['text'] = 'Play'
        counter = 1
        

def run():
    global counter
    while counter <= 5:
        print(counter)
        counter += 1
        time.sleep(0.5)

        if button_1['text'] == 'Play':
            break

        if counter > 5:
            main()
            break
window = tk.Tk()

button_1 = tk.Button(window, text='Play', command=main)
button_1.pack()

window.mainloop()
→ Ссылка
Автор решения: Levinson

Из документации threading:

A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property or the daemon constructor argument.

Note: Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.

Поэтому точно так-же, как и в скрытом смысле этой цитаты, советую ознакомиться с классом Event.

→ Ссылка