我注意到在通过python使用gstreamer之后(使用来自Ubuntu 14.04的python-gst-1.0 deb软件包版本1.2.0-1),我似乎每个编码器运行都有一个杂散线程。我在我编写的模块中有gstreamer接口,它在模块中执行gobject.mainloop,并且执行mainloop.quit(),所以我不希望它是mainloop本身。
几次运行后,threading.enumerate()显示:
[<_MainThread(MainThread, started 140079923849024)>,
<_DummyThread(Dummy-1, started daemon 140079768815360)>,
<_DummyThread(Dummy-3, started daemon 140079785338624)>,
<_DummyThread(Dummy-4, started daemon 140079418832640)>,
<_DummyThread(Dummy-2, started daemon 140079802386176)>]
值得庆幸的是,它们是以守护进程启动的,因此程序将退出,但我不知道如何清理它们。它们正在影响使用Ctrl-C退出脚本的可能性,因为KeyboardInterrupt似乎并不总是来到MainThread。我结束了我的运行循环:
try:
time.sleep(899.0)
except KeyboardInterrupt:
pass
time.sleep(1.0)
这应该允许我通过在第一次捕获try / except时快速按Ctrl-C两次来中止循环超时,并且第二次在1s睡眠时没有处理程序,因此退出。然而,对于杂散线程,第二个Ctrl-C在某种程度上从未在这个级别上看到,所以我需要Ctrl-Z来到shell并强制终止该脚本。我不喜欢它。
任何人都知道这个流浪线会是什么,以及如何让它合作并为我而死?我打算在正在运行的进程中打破gdb以确定它可能是什么。
类代码(剥离以删除不相关的部分):
class GstEncoder:
def __init__(self, metadata, mediainfo):
self.error = None
# used for controlling logic which I removed for clarity
self.metadata = metadata
self.mediainfo = mediainfo
# Create a pipeline in self.pipeline
self.setupPipeline()
# Put in the MainLoop
self.mainloop = GObject.MainLoop()
self.context = self.mainloop.get_context()
self.abort = False
def __del__(self):
logger.info("Dying gasp!")
if self.mainloop.is_running():
self.mainloop.quit()
self.pipeline.unref()
def start(self):
# Set in playing mode
self.pipeline.set_state(Gst.State.PLAYING)
# actually only used in some situations, removed the controlling logic for clarity
GObject.timeout_add_seconds(900, self.timedOut)
GObject.timeout_add_seconds(30, self.progressReport)
try:
self.abort = False
self.mainloop.run()
except KeyboardInterrupt:
logger.warning("Aborted by Ctrl-C")
self.abort = True
self.mainloop.quit()
raise KeyboardInterrupt
# Stop the pipeline
self.pipeline.set_state(Gst.State.NULL)
return self.error
def progressReport(self):
position = self.pipeline.query_position(Gst.Format.TIME)[1]
duration = self.pipeline.query_duration(Gst.Format.TIME)[1]
if self.abort:
return False
percentage = 0.0 if duration == 0 \
else float(position) / float(duration) * 100.0
logger.info("Progress: %s / %s (%.2f%%)" % (Gst.TIME_ARGS(position),
Gst.TIME_ARGS(duration), percentage))
return True
def timedOut(self):
if self.abort:
return False
self.error = "Aborted by watchdog timer"
logger.warning(self.error)
self.abort = True
self.mainloop.quit()
return False
这被实例化为:
err = None
# Filename, etc is in metadata
encoder = GstEncoder(metadata, mediainfo)
if encoder.error:
err = encoder.error
if not err:
err = encoder.start()
if err:
logger.error(err)
encoder = None
print threading.enumerate()
可在以下位置查看示例管道:https://s3.amazonaws.com/beirdo-share/before.png
答案 0 :(得分:1)
我遇到了一个听起来相同的问题:Ctrl-C触发KeyboardInterrupt
,但由于非守护进程gstreamer线程,进程无法退出。修复是在应用程序启动时调用GObject.threads_init()
一次。