操作系统:linux
Python版本:3.6
我正在尝试使用Python运行时扩展C应用程序。 C应用程序使用pthread
,而我尝试在Python运行时中使用multiprocessing
forkserver
,但遇到了问题。当我尝试使用SIGINT
信号杀死程序时(通过在终端中单击 Ctrl + C )杀死工作进程,但主程序挂起。 / p>
这是一个产生相同问题的玩具程序。
#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
信号,但似乎主信号无法接收信号。我如何才能使该应用程序在SIGINT
上正常死机而不会永远挂起?
通过阅读ViKiG答案,我意识到我可以首先在工作进程中捕获KeyboardInterrupt
(或SIGINT
)异常,并将一些哨兵值发送给主进程以通知该异常并关闭该应用程序。
浏览了CPython forkserver实现之后,我可能得出结论,该库的作者有意使主进程忽略了SIGINT
。我猜,目前,推荐的方法是在工作进程中而不是在主要进程中捕获异常。
答案 0 :(得分:1)
我将job
函数更改为处理CTRL+C
中断:
def job():
import time
try:
while True:
print("running..")
time.sleep(5)
except KeyboardInterrupt:
print 'Exiting job..'
上述更改后,我的测试程序可以正常退出。
编辑后:
我将此添加到了C程序
#include<signal.h>
void handler() {printf("Exiting main.."); exit(0);}
将main
修改为:
int main() {
signal(SIGINT, handler);
答案 1 :(得分:1)
Py_Initialize()
将安装python自己的单个处理程序,而是调用Py_InitializeEx(0)
:
void Py_InitializeEx(int initsigs)
此功能类似于 如果initsigs为1,则为Py_Initialize()。如果initsigs为0,则跳过 信号处理程序的初始化注册,这可能会有用 嵌入Python时。
详细了解其doc和cpython source。
答案 2 :(得分:0)
事实证明,我不必在主要过程中捕获异常。我通过在工作进程中捕获short
(或KeyboardInterrupt
)异常并向主进程发送一些哨兵值来通知该异常并关闭应用程序,从而解决了该问题。
SIGINT