Python gstreamer 使用中的多余线程
我注意到在用Python使用gstreamer后(我用的是Ubuntu 14.04的python-gst-1.0 deb包版本1.2.0-1),每次运行编码器时似乎都会产生一个多余的线程。我在一个我写的模块里使用gstreamer接口,并且在这个模块里运行gobject.mainloop,并且调用了mainloop.quit(),所以我不认为问题出在主循环上。
经过几次运行,使用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似乎并不总是能传递到主线程。我结束运行循环的方式是:
try:
time.sleep(899.0)
except KeyboardInterrupt:
pass
time.sleep(1.0)
这样我可以通过快速按两次Ctrl-C来中断循环的超时,第一次会捕获try/except,第二次在1秒的休眠上没有处理器,因此会退出。然而,由于这些多余的线程,第二次Ctrl-C在这个层面上似乎从未被看到,所以我需要按Ctrl-Z回到命令行,然后强制结束脚本。我对此很不满意。
有没有人知道这个多余的线程是什么,怎么让它配合并结束?我准备在一个正在运行的进程上使用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
1 个回答
1
我遇到了一个类似的问题:按下 Ctrl-C 会触发一个 KeyboardInterrupt
,但是程序并没有退出,因为有一些非守护线程在运行。解决这个问题的方法是在应用程序启动时调用一次 GObject.threads_init()
。