python - 无法在嵌入 Python 的多线程 C 应用程序中终止多处理池

标签 python c multithreading multiprocessing python-c-api

操作系统:Linux
Python版本:3.6

我正在尝试使用 Python 运行时扩展 C 应用程序。 C 应用程序使用 pthread,我尝试在 Python 运行时使用 multiprocessing forkserver 但遇到了问题。当我尝试用 SIGINT 信号终止程序时(通过在终端中点击 Ctrl+C ),工作进程被终止但主程序挂起。

这是一个会产生相同问题的玩具程序。

#include <Python.h>
#include <pthread.h>

void * thread_start(void *unsed)
{
    PyObject *fs_mod = PyImport_AddModule("fs");
    PyObject *apply_fn = PyObject_GetAttrString(fs_mod, "apply");
    PyObject *job_fn = PyObject_GetAttrString(fs_mod, "job");
    PyObject *job_args = Py_BuildValue("()");
    PyObject_CallFunctionObjArgs(apply_fn, job_fn, job_args, NULL);
    printf("finished\n");
    return NULL;
}

int main(){
    Py_Initialize();
    PyRun_SimpleString(
        "import sys; sys.path.append('...');"
        "sys.argv=['a.out'];"  // prepare a dummy argument to avoid error in forkserver
        "import fs\n"
        "if __name__ == '__main__': fs.init()");

    while(1){
        pthread_t thread;
        pthread_create(&thread, 0, &thread_start, NULL);
        printf("joing\n");
        pthread_join(thread, 0);
    }
}
import multiprocessing as mp

pool = None


def job():
    import time
    print("running..")
    time.sleep(5)

def init():
    global pool
    mp.set_start_method('forkserver')
    pool = mp.Pool(1)

def apply(*args):
    global pool
    return pool.apply(*args)

我不太清楚 Linux 信号是如何工作的。我试图用信号模块在主 python 进程中捕获 SIGINT 信号,但似乎 main 它没有接收到信号。我怎样才能让这个应用程序在 SIGINT 上优雅地死去,而不是永远挂起?


通过阅读 ViKiG 的回答,我意识到我可以首先捕获工作进程中的 KeyboardInterrupt(或 SIGINT)异常并将一些哨兵值发送到主进程以通知异常并关闭应用程序。

在浏览了 CPython forkserver 实现之后,我可能得出结论,库的作者故意让主进程忽略 SIGINT。我想,目前,推荐的方法是在工作进程中捕获异常,而不是在主进程中。

最佳答案

Py_Initialize() 将安装 python 自己的信号处理程序,调用 Py_InitializeEx(0) 代替:

void Py_InitializeEx(int initsigs)

This function works like Py_Initialize() if initsigs is 1. If initsigs is 0, it skips initialization registration of signal handlers, which might be useful when Python is embedded.

查看更多信息 doc , 和 cpython source .

关于python - 无法在嵌入 Python 的多线程 C 应用程序中终止多处理池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51978956/

相关文章:

python - 使用Scrapy爬取多个域,无需纵横交错

python - 按顺序对列表进行排序,但删除稍后出现的较低值

Python mongodb create_index错误

iphone - 即时创建 *.docx(也许还有 *.doc?)文档?

java - 对远程对象 Java RMI 的并发访问

Python制表小数位数

c - 如何在c中编写一个读取数组的函数?

C 语言的凯撒密码

Python多线程文件处理

c# - 如何在多个线程之间进行通信?