Python gstreamer使用的杂散线程

时间:2014-11-02 05:37:04

标签: python multithreading gstreamer

我注意到在通过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

1 个答案:

答案 0 :(得分:1)

我遇到了一个听起来相同的问题:Ctrl-C触发KeyboardInterrupt,但由于非守护进程gstreamer线程,进程无法退出。修复是在应用程序启动时调用GObject.threads_init()一次。