我正在尝试弄清楚如何使用 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")
有人有什么建议或想法吗?谢谢。
不可能向另一个线程发送信号,因此你需要做其他事情。
您可能会使用此 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()
这些线程将在主线程退出时退出,无需您进行任何额外的干预。
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
有没有一种方法可以只向一个线程发送信号而不影响其他线程?
我不是Python专家,但如果我试图解决你的问题,在阅读了Python3中的信号处理之后,我会开始计划使用多个进程,而不是在单个进程中使用多个线程。