[英]Segmentation fault when calling C function with Python C API twice
Recently I wanted to call Python from Fortran (see here ) using a C wrapper. 最近我想使用C包装器从Fortran调用Python(见这里 )。 Below I post a simpler example.
下面我发布一个更简单的例子。 Second call of the function results in Segmentation fault at
pModule = PyImport_Import(pName)
. 函数的第二次调用导致
pModule = PyImport_Import(pName)
处的分段错误。 I figured out that the problem is with the from scipy.optimize import newton
line - if I comment it everything works fine. 我发现问题是
from scipy.optimize import newton
线 - 如果我评论它一切正常。 Any ideas how to fix it? 任何想法如何解决它?
rootC.c rootC.c
#include "rootC.h"
#include <Python.h>
void root_(double* A, double* B, double* t, double* x)
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue, *sys, *path;
Py_Initialize();
sys = PyImport_ImportModule("sys");
path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyString_FromString("."));
pName = PyString_FromString("rootPY");
pModule = PyImport_Import(pName);
if (!pModule)
{
PyErr_Print();
printf("ERROR in pModule\n");
exit(1);
}
pFunc = PyObject_GetAttrString(pModule, "root");
pArgs = PyTuple_New(3);
PyTuple_SetItem(pArgs, 0, PyFloat_FromDouble((*A)));
PyTuple_SetItem(pArgs, 1, PyFloat_FromDouble((*B)));
PyTuple_SetItem(pArgs, 2, PyFloat_FromDouble((*t)));
pValue = PyObject_CallObject(pFunc, pArgs);
*x = PyFloat_AsDouble(pValue);
Py_Finalize();
}
rootC.h rootC.h
#ifndef ROOT_H_
#define ROOT_H_
void root_(double*, double*, double*, double*);
#endif
rootPY.py rootPY.py
from mpmath import polylog, exp
from scipy.optimize import newton
def root(A,B,t):
return 1
main.c main.c中
#include "rootC.h"
#include <stdio.h>
int main()
{
double A = 0.4, B = 0.3, t = 0.1, x = 0.0;
root_(&A,&B,&t,&x);
printf("x = %.15f\n", x);
root_(&A,&B,&t,&x);
printf("x = %.15f\n", x);
return 0;
}
Makefile Makefile文件
CC = gcc
FC = gfortran
CFLAGS = -I/usr/include/python2.7
LFLAGS = -L/usr/local/lib -lpython2.7 -lm
.PHONY: all clean
all: main
main: main.o rootC.o
$(CC) $^ -o $@ $(LFLAGS)
main.o: main.c
$(CC) $(CFLAGS) -c $< -o $@
rootC.o: rootC.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o
One can also do something like this: 人们也可以这样做:
#include "rootC.h"
#include <Python.h>
#include <stdlib.h>
void Initialize ()
{
Py_Initialize();
}
void Finalize ()
{
Py_Finalize();
}
void root_(double* A, double* B, double* t, double* x)
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue, *sys, *path;
static int i;
if (i == 0)
{
++i;
Initialize();
atexit(Finalize);
}
....
}
The issue is with initializing and finalizing your python shell every time the function is called. 问题是每次调用函数时初始化和完成python shell。 (it is trying to initialise a .dll more than once)
(它试图不止一次初始化.dll)
Edit: Link to resource 编辑: 链接到资源
This is my fix... ( not the best code for the job) in your main.c 这是我在main.c中的修复...(不是作业的最佳代码)
int main()
{
double A = 0.4, B = 0.3, t = 0.1, x = 0.0;
bool Stop = false;
root_(&A,&B,&t,&x,&Stop);
printf("x = %.15f\n", x);
Stop=true;
root_(&A,&B,&t,&x,&Stop);
printf("x = %.15f\n", x);
return 0;
}
then in your rootC.h 然后在你的rootC.h中
void root_(double*, double*, double*, double*,bool*);
then in rootC.c 然后在rootC.c中
#include "rootC.h"
#include <Python.h>
void root_(double* A, double* B, double* t, double* x,bool* Stop)
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue, *sys, *path;
if (*Stop==false)
{
Py_Initialize();
}
sys = PyImport_ImportModule("sys");
path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyString_FromString("."));
pName = PyString_FromString("rootPY");
pModule = PyImport_Import(pName);
if (!pModule)
{
PyErr_Print();
printf("ERROR in pModule\n");
exit(1);
}
pFunc = PyObject_GetAttrString(pModule, "root");
pArgs = PyTuple_New(3);
PyTuple_SetItem(pArgs, 0, PyFloat_FromDouble((*A)));
PyTuple_SetItem(pArgs, 1, PyFloat_FromDouble((*B)));
PyTuple_SetItem(pArgs, 2, PyFloat_FromDouble((*t)));
pValue = PyObject_CallObject(pFunc, pArgs);
*x = PyFloat_AsDouble(pValue);
if (*Stop==true)
{
Py_Finalize();
}
}
This should work :) 这应该工作:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.