所以我到目前为止所做的是构建一个小的ctypes和python代码,它执行以下操作:
Python使用指向void指针的指针作为参数调用C函数。
C代码创建一个类型ReturnStruct
的结构并实例化它,然后它的数据成员将python传入的指针设置为指向此结构。
Python多次调用另一个C函数来增加某些值。
Python然后检查值。
Python调用C函数来解除分配结构指针。
到目前为止,我已经完成了前3个阶段的工作,但我在最后两个部分遇到了问题。这是C代码:
#include <stdio.h>
#include <stdlib.h>
//#include "runSolver.h"
#define SMB_MAX_DATA_SIZE 16
typedef struct testStruct {
double *x[11];
double *u[10];
} Test;
typedef struct returnStruct_t {
Test* vars;
} ReturnStruct;
void initalize_returnStruct(void** returnStruct){
ReturnStruct* new_returnStruct = (ReturnStruct *)malloc(sizeof(ReturnStruct));
Test* varsStruct = (Test*)malloc(sizeof(Test)*3);
int dataSize = 5;
int i;
for(i = 0; i < 3; i++){
int x;
for(x = 0; x < 11; x++)
varsStruct[i].x[x] = (double *)malloc(sizeof(double)*5);
for(x = 0; x < 10; x++)
varsStruct[i].u[x] = (double *)malloc(sizeof(double)*5);
}
new_returnStruct->vars = varsStruct;
*returnStruct = new_returnStruct;
}
void free_returnStruct(void* data){
ReturnStruct* returnStruct = data;
int i;
for(i = 0; i < 3; i++){
int x;
for(x = 1; x < 11; x++)
free(returnStruct->vars[i].x[x]);
for(x = 0; x < 10; x++)
free(returnStruct->vars[i].u[x]);
}
free(returnStruct->vars);
free(returnStruct);
}
void parallelSolver(void* data){
ReturnStruct* VarsArray = data;
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].x[0][0]);
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].x[10][4]);
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].u[0][0]);
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].u[9][2]);
VarsArray->vars[0].x[0][0] += 20.0;
VarsArray->vars[0].x[10][4] += 203.0;
VarsArray->vars[0].u[0][0] += 202.0;
VarsArray->vars[0].u[9][2] += 202.0;
}
这是python代码:
#!/usr/bin/python
import sys
import ctypes as ct
numOpt = 3
class vars_t(ct.Structure):
_fields_ = [("u", ct.POINTER(ct.c_double*10)),
("x", ct.POINTER(ct.c_double*11))]
class returnStruct_t(ct.Structure):
_fields_ = [("vars", vars_t*numOpt)]
runSolver = ct.CDLL('./runSolverParallel.so')
returnStructPointer = ct.POINTER(returnStruct_t)
runSolver.parallelSolver.argtypes = [ct.c_void_p()]
varsd = ct.c_void_p()
runSolver.initalize_returnStruct(ct.byref(varsd))
runSolver.parallelSolver(varsd)
runSolver.parallelSolver(varsd)
runSolver.parallelSolver(varsd)
runSolver.parallelSolver(varsd)
varsdb = ct.cast(varsd, returnStruct_t)
print(varsdb.contents.vars[0].x[0][0])
runSolver.free_returnStruct(varsd)
代码运行良好,直到我到达这三行:
varsdb = ct.cast(varsd, returnStruct_t)
print(varsdb.contents.vars[0].x[0][0])
runSolver.free_returnStruct(varsd)
所有这些都会产生seg错误。关于如何正常工作的任何建议将不胜感激!
错误如下所示:
Starting program: /usr/bin/python UserDefinedCode.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
This is the value: 0.000000
This is the value: 0.000000
This is the value: 0.000000
This is the value: 0.000000
This is the value: 20.000000
This is the value: 203.000000
This is the value: 202.000000
This is the value: 202.000000
This is the value: 40.000000
This is the value: 406.000000
This is the value: 404.000000
This is the value: 404.000000
This is the value: 60.000000
This is the value: 609.000000
This is the value: 606.000000
This is the value: 606.000000
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff33795d4 in ?? () from /usr/lib/python2.7/lib-dynload/_ctypes.so
(gdb) where
#0 0x00007ffff33795d4 in ?? () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#1 0x00007ffff3386ea4 in ffi_call_unix64 () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#2 0x00007ffff33868c5 in ffi_call () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#3 0x00007ffff33772c2 in _ctypes_callproc () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#4 0x00007ffff3377aa2 in ?? () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#5 0x00000000004d91b6 in PyObject_Call ()
#6 0x000000000054c0da in PyEval_EvalFrameEx ()
#7 0x000000000054c272 in PyEval_EvalFrameEx ()
#8 0x0000000000575d92 in PyEval_EvalCodeEx ()
#9 0x00000000004c1352 in PyRun_SimpleFileExFlags ()
#10 0x00000000004c754f in Py_Main ()
#11 0x00007ffff68cb76d in __libc_start_main (main=0x41ba10 <main>, argc=2, ubp_av=0x7fffffffe1d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe1c8)
at libc-start.c:226
#12 0x000000000041ba41 in _start ()
答案 0 :(得分:2)
这里至少有四个问题(实际上,五个,但一个不相关)。
导致你的段错误的那条线是这样的:
varsdb = ct.cast(varsd, returnStruct_t)
这是因为您尝试将void *
投射到returnStruct_t
,而不是returnStruct_t *
。由于returnStruct_t
远大于指针,因此很可能会在分配的页面结束时运行。即使它不是段错误,它也会给你垃圾值。它等同于这个C代码:
returnStruct_t varsdb = *(returnStruct_t *)(&varsd);
你想要的是相当于:
returnStruct_t *varsdb = (returnStruct_t *)(varsd);
换句话说:
varsdb = ct.cast(varsd, returnStructPointer)
在修复之后,我经常(但并非总是)在尝试访问varsdb.contents.vars[0].x[0][0]
后仍然会遇到段错误(varsdb.contents.vars[0].x[0]
本身总是安全的。)
下一个问题是你没有正确定义你的结构。这是C:
typedef struct testStruct {
double *x[11];
double *u[10];
} Test;
这是Python:
class vars_t(ct.Structure):
_fields_ = [("u", ct.POINTER(ct.c_double*10)),
("x", ct.POINTER(ct.c_double*11))]
你混淆了u
和x
。所以,你所谓的x
,并且被视为11个双打的数组,实际上是u
,一个10个双打的数组。因此,每当你触摸x [10]时,你就会越过数组的末尾。
修好那个之后,我打印出垃圾值。使用clang
版本,它始终接近6.92987533417e-310
。
我认为这个纯粹是在C代码中。我经常从C中的x[10][4]
和u[9][2]
行打印出垃圾数字。再次,使用相同的构建,我得到了合理值的相同组合,如26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192.000000
这两个数字,以及前者的合理值,但后者为nan
。
当我在valgrind
下运行一个简单的C驱动程序时,每四分之一fprintf
我得到这个:
==85323== Use of uninitialised value of size 8
所以你可能在C中的分配或初始化代码中出现了一个错误的错误,有时你却不会总是侥幸逃脱。
此外,这些类型不同:
typedef struct returnStruct_t {
Test* vars;
} ReturnStruct;
class returnStruct_t(ct.Structure):
_fields_ = [("vars", vars_t*numOpt)]
前者是一个长指针,指针指向Test
个对象的数组。后者是3个Test
个对象。所以,再次,你试图读取指向某个东西的指针作为该类型的值,并且在这里你将超过分配值的末尾。
修好之后,我不会再遇到任何崩溃,即使我沿途收到垃圾打印件,我也会获得合理的最终值,例如80.0
。但当然我仍然会在途中得到那些垃圾打印件,而valgrind仍在抱怨,所以显然这仍然不是最后一个问题。
你的代码中也有明显的泄漏 - 这与问题没有直接关系,但这是一个很好的迹象,表明你可能在其他地方遇到过类似的错误。您可以像这样分配x
数组:
for(x = 0; x < 11; x++)
varsStruct[i].x[x] = (double *)malloc(sizeof(double)*5);
...然后像这样释放他们:
for(x = 1; x < 11; x++)
free(returnStruct->vars[i].x[x]);
所以x[0]
永远不会被释放。