如何在Python中向各个线程发送CTRL-C信号?

问题描述 投票:0回答:3

我正在尝试弄清楚如何使用 Python 在 Windows 上正确发送 CTRL-C 信号。早些时候,我正在摆弄 youtube-dl 并将其嵌入到 PyQt Qthread 中进行处理,并创建了一个停止按钮来停止线程,但是当尝试下载直播时,即使关闭应用程序后,我也无法让 FFMPEG 停止,并且我必须手动终止每次都会破坏视频的进程。
我知道我必须以某种方式向它发送 CTRL-C 信号,并最终使用了它。

os.kill(signal.CTRL_C_EVENT, 0)

我实际上能够让它工作,但如果你尝试下载多个视频并尝试使用上述信号停止其中一个线程,它会杀死所有下载。
有没有一种方法可以将信号发送到一个线程而不影响其他线程?
下面是一些具有 2 个独立线程的常规 Python 代码的示例,其中 10 秒后在 thread_2 中触发 CTRL-C 信号,最终杀死 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")

有人有什么建议或想法吗?谢谢。

python windows multithreading winapi
3个回答
8
投票

不可能向另一个线程发送信号,因此你需要做其他事情。

您可能会使用此 hack 在另一个线程中引发异常(我不会在此处复制源代码,因为它带有 MIT 许可证): http://tomerfiliba.com/recipes/Thread2/(链接已失效)

这样,您就可以向另一个线程发送 KeyboardInterrupt 异常,无论如何,这就是使用 Ctrl-C 时发生的情况。

虽然这看起来可以满足您的要求,但它仍然会破坏当前正在下载的视频。


另一方面,由于您似乎只对主线程退出时杀死所有线程感兴趣,因此可以通过更简单的方式完成:

将所有线程配置为守护进程,例如:

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

这些线程将在主线程退出时退出,无需您进行任何额外的干预。


1
投票

您可以使用

signal.pthread_kill

from signal import pthread_kill, SIGTSTP
from threading import Thread
from itertools import count
from time import sleep

def target():
    for num in count():
        print(num)
        sleep(1)

thread = Thread(target=target)
thread.start()
sleep(5)
pthread_kill(thread.ident, SIGTSTP)

结果

0
1
2
3
4

[14]+  Stopped

0
投票

有没有一种方法可以只向一个线程发送信号而不影响其他线程?

我不是Python专家,但如果我试图解决你的问题,在阅读了Python3中的信号处理之后,我会开始计划使用多个进程,而不是在单个进程中使用多个线程。

© www.soinside.com 2019 - 2024. All rights reserved.