Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send a CTRL-C signal to individual threads in Python?

I am trying to figure out how to properly send a CTRL-C signal on Windows using Python. Earlier I was messing around with youtube-dl and embedded it into a PyQt Qthread to do the processing and created a stop button to stop the thread but when trying to download a livestream I was unable to get FFMPEG to stop even after closing the application and I'd have to manually kill the process which breaks the video every time.
I knew I'd have to send it a CTRL-C signal somehow and ended up using this.

os.kill(signal.CTRL_C_EVENT, 0)

I was actually able to get it to work but if you try to download more than one video and try to stop one of the threads with the above signal it would kill all the downloads.
Is there any way to send the signal to just one thread without effecting the others?
Here is an example of some regular Python code with 2 seperate threads where the CTRL-C signal is fired in thread_2 after 10 seconds which ends up killing thread_1.

import os
import signal
import threading
import time
import youtube_dl

def thread_1():
    print("thread_1 running")
    url = 'https://www.cbsnews.com/common/video/cbsn_header_prod.m3u8'
    path = 'C:\\Users\\Richard\\Desktop\\'
    ydl_opts = {
        'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
        'outtmpl': '{0}%(title)s-%(id)s.%(ext)s'.format(path),
        'nopart': True,
    }
    ydl_opts = ydl_opts
    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
        try:
            ydl.download([url])
        except KeyboardInterrupt:
            print('stopped')

def thread_2():
    print("thread_2 running")
    time.sleep(10)
    os.kill(signal.CTRL_C_EVENT, 0)

def launch_thread(target, message, args=[], kwargs={}):
    def thread_msg(*args, **kwargs):
        target(*args, **kwargs)
        print(message)
    thread = threading.Thread(target=thread_msg, args=args, kwargs=kwargs)
    thread.start()
    return thread

if __name__ == '__main__':
    thread1 = launch_thread(thread_1, "finished thread_1")
    thread2 = launch_thread(thread_2, "finished thread_2")

Does anyone have any suggestions or ideas? Thanks.

like image 498
Richard Avatar asked Jun 10 '18 22:06

Richard


People also ask

How do you send a message between threads in python?

Perhaps the safest way to send data from one thread to another is to use a Queue from the queue library. To do this, create a Queue instance that is shared by the threads. Threads then use put() or get() operations to add or remove items from the queue as shown in the code given below.

How do you control a thread in Python?

So in summary, when programming in Python: Use multithreading when you know the program will be waiting around for some external event (i.e., for I/O-bound tasks). Use multiprocessing when your code can safely use multiple cores and manage memory (i.e., for CPU-bound tasks).

How do you multi thread a python script?

Multithreading in Python By default, your Python programs have a single thread, called the main thread. You can create threads by passing a function to the Thread() constructor or by inheriting the Thread class and overriding the run() method.


1 Answers

It is not possible to send signals to another thread, so you need to do something else.

You could possibly raise an exception in another thread, using this hack (for which I won't copy the source here because it comes with an MIT license): http://tomerfiliba.com/recipes/Thread2/

With that, you could send a KeyboardInterrupt exception to the other thread, which is what happens with Ctrl-C anyway.

While it seems like this would do what you want, it would still break the video which is currently downloading.


On the other hand, since you seem to only be interested in killing all threads when the main thread exits, that can be done in a much simpler way:

Configure all threads as daemons, e.g.:

thread = threading.Thread(target=thread_msg, args=args, kwargs=kwargs)
thread.daemon = True
thread.start()

These threads will exit when the main thread exits, without any additional intervention needed from you.

like image 121
zvone Avatar answered Oct 07 '22 00:10

zvone