Python C API 和 gnuradio,Python 启动在 Py_Finalize() 之后不终止的线程

Python C API and gnuradio, Python starts threads that don't terminate after Py_Finalize()

当我从 C 代码启动 python 代码时,有许多线程在 Python 代码执行结束时不会停止:

    ps -T 20402
    PID    SPID TTY      STAT   TIME COMMAND
  20402   20402 pts/0    Rl     0:11 ./test
  20402   20427 pts/0    Sl     0:00 ./test
  20402   20428 pts/0    Sl     0:00 ./test
  20402   20443 pts/0    Sl     0:00 ./test
  20402   20458 pts/0    Sl     0:00 ./test
  20402   20461 pts/0    Sl     0:00 ./test
  20402   20464 pts/0    Sl     0:00 ./test
  20402   20471 pts/0    Sl     0:00 ./test

这些线程似乎与 gnuradio 相关库的使用有关。 这是我在 Python:

中的代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph
# Title: Weather satellite
# Author: Norian
# GNU Radio version: 3.8.1.0

from gnuradio import analog
from gnuradio import blocks
from gnuradio import filter
from gnuradio.filter import firdes
from gnuradio import gr
import sys
import signal
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
import osmosdr
import time

class Weather_sat(gr.top_block):

    def __init__(self):
        gr.top_block.__init__(self, "Weather satellite")

        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate = 1411200

        ##################################################
        # Blocks
        ##################################################
        self.rational_resampler_xxx_0 = filter.rational_resampler_fff(
                interpolation=208,
                decimation=441,
                taps=None,
                fractional_bw=None)
        self.osmosdr_source_0 = osmosdr.source(
            args="numchan=" + str(1) + " " + ""
        )
        self.osmosdr_source_0.set_time_now(osmosdr.time_spec_t(time.time()), osmosdr.ALL_MBOARDS)
        self.osmosdr_source_0.set_sample_rate(samp_rate)
        self.osmosdr_source_0.set_center_freq(137100000, 0)
        self.osmosdr_source_0.set_freq_corr(0, 0)
        self.osmosdr_source_0.set_gain(40, 0)
        self.osmosdr_source_0.set_if_gain(20, 0)
        self.osmosdr_source_0.set_bb_gain(20, 0)
        self.osmosdr_source_0.set_antenna('', 0)
        self.osmosdr_source_0.set_bandwidth(0, 0)
        self.low_pass_filter_0 = filter.fir_filter_ccf(
            16,
            firdes.low_pass(
                1,
                samp_rate,
                110000,
                10000,
                firdes.WIN_HAMMING,
                6.76))
        self.blocks_wavfile_sink_0 = blocks.wavfile_sink('/home/norian/Documents/GNURADIO/noaadeu.wav', 1, 20800, 16)
        self.analog_wfm_rcv_0 = analog.wfm_rcv(
            quad_rate=88200,
            audio_decimation=2,
        )



        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_wfm_rcv_0, 0), (self.rational_resampler_xxx_0, 0))
        self.connect((self.low_pass_filter_0, 0), (self.analog_wfm_rcv_0, 0))
        self.connect((self.osmosdr_source_0, 0), (self.low_pass_filter_0, 0))
        self.connect((self.rational_resampler_xxx_0, 0), (self.blocks_wavfile_sink_0, 0))

    def get_samp_rate(self):
        return self.samp_rate

    def set_samp_rate(self, samp_rate):
        self.samp_rate = samp_rate
        self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.samp_rate, 110000, 10000, firdes.WIN_HAMMING, 6.76))
        self.osmosdr_source_0.set_sample_rate(self.samp_rate)



def main(freq):
    top_block_cls=Weather_sat
    tb = top_block_cls()

    def sig_handler(sig=None, frame=None):
        tb.stop()
        tb.wait()
        sys.exit(0)

    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)

    tb.start()
    try:
        input('Press Enter to quit: ')
    except EOFError:
        pass
    tb.stop()
    tb.wait()

这是我的 C 代码:

//prgm.c
#include <stdio.h>
#include "Python.h"

int main(void) {
    Py_Initialize();

    /* add . to the path */
    PyObject* sys = PyImport_ImportModule("sys");
    PyObject* path = PyObject_GetAttrString(sys, "path");
    PyList_Insert(path, 0, PyUnicode_FromString("."));

    /* import desired function */
    PyObject* pModule = PyImport_ImportModule("main");
    PyObject* pFunc = PyObject_GetAttrString(pModule, "main");

    /* call it */
    PyObject* pArgs = Py_BuildValue("(s)", "137912500");
    PyObject_CallObject(pFunc, pArgs);
    Py_Finalize();
    fprintf(stderr,"End of python software");
    while(1);
    return 0;
}

你能给我解释一下如何检测由 python 创建的线程并杀死它们吗?

我正在研究 Ubuntu 20.4。 我使用的是 gnuradio 3.8 版,我是从 apt 安装的。

非常感谢您的帮助。

Perhaps gnuradio creates threads from its own C API? – user23952

没错。 GNU Radio 是一个高度多线程的应用程序。

Can you explain to me how to detect threads created by python and kill them?

你可以“杀死”进程,你不能“杀死”线程 - 你可以 interrupt/join 它们(这在某种意义上是类似的,这意味着它们不再被调度,但不同的是分配给它们的资源不会消失的感觉——因为线程不拥有自己的资源(除了堆栈),而是进程。

请注意,现有线程本身并不是天生的问题 - 一个程序有休眠线程是完全正常的,这些线程在退出时被操作系统清理,而不是更早;线程有多种用途,包括处理信号、等待 RPC 连接、管理其他资源......这些在您的情况下甚至可能不会发生。

Do you know how to exit the gr-osmosdr block properly?

这很可能是osmosdr源码封装的具体驱动源码的问题

可能这一切都“正常”退出,您实际上并没有描述任何出错的地方!