user2073791
user2073791

Reputation: 11

Python: Kill thread after loop/Pause execution of Thread

As a new programmer, I'm trying to create a Python3 script that creates a Countdown timer based on the KeyCombination used which is then written to a text file used by StreamlabsOBS. The idea is that when a KeyCombo is pressed (e.g ctrl+alt+z) a function starts a timer, and at the same time, another function writes the current time in the countdown to a txt file. This script would ideally be running during the entire stream.

So far, I can get the countdown working and writing to the file exactly how I want it to. But it seems the Thread is still alive after finishing the countdown. I'm not sure if this is a problem or not. Another thing is that I want to implement some kind of pause feature, that would pause the timer function. I'm not sure how to even start on that part.

The print statements are for me to know what part of the function I am at.

from pynput import keyboard
from pathlib import Path
from threading import Thread
import queue
from time import sleep

script_location = Path(__file__).absolute().parent
timer_queue = queue.Queue()


def storeInQueue(function):
    print("Sent Start Thread msg")
    def storer(*args):
        for time in function(*args):
            timer_queue.put(time)
            print(f"stored {time}")
        
    return storer

@storeInQueue
def timer(t):
    print("Iterating Timer Loop")
    while t > -1:
        yield t
        sleep(1)
        t -= 1
        



def speakKorean():
    print("starting Thread")
    timer_thread = Thread(target=timer, args=(5,))
    timer_thread.start()
    ctime = timer_queue.get()
    while ctime >-1:
        with open(script_location / 'ChronoDown.txt', "w") as timer_file:
            timer_file.write(f"Speak Korean for {ctime}s")
            timer_file.flush()
        sleep(1)
        ctime = timer_queue.get()
        if ctime == 0: break
    print('Speak Korean done!')
    with open(script_location / 'ChronoDown.txt', "w") as timer_file:
            timer_file.write(f"Done!")
            timer_file.flush()
    while timer_thread.is_alive:
        print("timer thread still running?")
        timer_thread.join()
        break
    if timer_thread.is_alive:
        print("didn't work")
    
    



def on_activate_z():
    timer_file = open(script_location / 'ChronoDown.txt', "w")
    timer_file.write("other keywords")
    timer_file.close()

        
def on_activate_c():
    korean_thread = Thread(target=speakKorean,)
    korean_thread.start()
    print("Working")
  


def on_activate_x():
    timer_file = open(script_location / 'ChronoDown.txt', "w")
    timer_file.write("No cursing for time")
    timer_file.close()


with keyboard.GlobalHotKeys({
        '<ctrl>+<alt>+z': on_activate_z,'<ctrl>+<alt>+c': on_activate_c,
        '<ctrl>+<alt>+x': on_activate_x}) as h:
    h.join() 

My console output looks like this after I run it. I'm not sure why "Sent Start Thread msg" sends before I start thread too.

Sent Start Thread msg
starting Thread
Working
Iterating Timer Loop
stored 5
stored 4
stored 3
stored 2
stored 1
stored 0
Speak Korean done!
timer thread still running?
didn't work 

Also if you have any optimization tips that would be appreciated. Thank you in advance for any help.

Upvotes: 0

Views: 116

Answers (1)

user2073791
user2073791

Reputation: 11

Thanks to @furas , I've now implemented a pause function that properly resumes as well. This is my updated code :

from pynput import keyboard
from pathlib import Path
from threading import Thread
import queue
from time import sleep

script_location = Path(__file__).absolute().parent
timer_queue = queue.Queue()
paused = False

while paused == False:
    def storeInQueue(function):
        print("Sent Start Thread msg")
        def storer(*args):
            for time in function(*args):
                timer_queue.put(time)
                print(f"stored {time}")
            
        return storer

    @storeInQueue
    def timer(t):
        print("Iterating Timer Loop")
        while t > -1:
            if paused == False:
                yield t
                sleep(1)
                t -= 1
            else: continue
            



    def speakKorean():
        print("starting Thread")
        timer_thread = Thread(target=timer, args=(5,))
        timer_thread.start()
        ctime = timer_queue.get()
        while ctime >-1:
            with open(script_location / 'ChronoDown.txt', "w") as timer_file:
                timer_file.write(f"Speak Korean for {ctime}s")
                timer_file.flush()
            sleep(1)
            ctime = timer_queue.get()
            if ctime == 0: break
        print('Speak Korean done!')
        with open(script_location / 'ChronoDown.txt', "w") as timer_file:
                timer_file.write(f"Done!")
                timer_file.flush()
        timer_thread.join()
        if timer_thread.is_alive():
            print("didn't work")
        else: print("its dead")
        



    def on_activate_z():
        global paused
        timer_file = open(script_location / 'ChronoDown.txt', "w")
        timer_file.write("Paused")
        timer_file.close()
        if paused == True:
            paused = False
            print(f'Paused = {paused}')
        else: 
            paused =True
            print(f'Paused = {paused}')

            
    def on_activate_c():
        korean_thread = Thread(target=speakKorean,)
        korean_thread.start()
        print("Working")
    


    def on_activate_x():
        timer_file = open(script_location / 'ChronoDown.txt', "w")
        timer_file.write("No cursing for time")
        timer_file.close()



    with keyboard.GlobalHotKeys({
            '<ctrl>+<alt>+z': on_activate_z,'<ctrl>+<alt>+c': on_activate_c,
            '<ctrl>+<alt>+x': on_activate_x}) as h:
        h.join()

The main differences:

  1. My entire code is now encapsulated in a While paused == False loop, which allows me to pause my timer function based on the state of paused using an if statement

  2. I've added the missing ( ) to timer_thread.is_alive() which allowed me to properly end the timer Thread

Upvotes: 1

Related Questions