[从Python调用时C DLL破裂

问题描述 投票:0回答:1

我有一个使用C / Python API嵌入Python解释器的DLL。如果调用DLL一次,则DLL可以正常工作,但是如果调用DLL两次,则代码会破解,并且我的程序会捕获内存错误。调用DLL的C代码很简单,并且一次调用DLL函数(调用Python解释器),如果未注释第二个调用(在代码中),代码将破解,并且仅当调用“ Numpy”时才会发生Python代码。

#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <dll_simples.h>

int main() {
double in[] = { 4,2,5,4,2 };
double out[5] = {};
double a = 0;
double b = 0;


simuser(a,b,in,out);
//simuser(a, b, in, out); IF NOT COMMENTED -> ERROR

return 0;
 }

我按照建议的here注释了DLL中的Py_Finalize(),此帖子here证实了来自Py_Finalize()文档的“如果某些扩展名的初始化例程被多次调用,它们可能无法正常工作;这种情况可能会发生如果应用程序多次调用Py_Initialize()和Py_Finalize()。”因此,我想知道为什么会发生这种情况,以及是否可以做其他任何事情,但在上一次对DLL的调用中只调用了一次“ Py_Finalize()”。

python c dll interpreter
1个回答
0
投票

列出[Python 3.Docs]: ctypes - A foreign function library for Python

dll00.h

#pragma once

#if defined(_WIN32)
#  if defined DLL0_EXPORTS
#    define DLL00_EXPORT_API __declspec(dllexport)
#  else
#    define DLL00_EXPORT_API __declspec(dllimport)
#  endif
#else
#  define DLL00_EXPORT_API
#endif


#if defined(__cplusplus)
extern "C" {
#endif

DLL00_EXPORT_API int dll00Func00(double t, double delta, unsigned int size, const double *pIn, double *pOut);

#if defined(__cplusplus)
}
#endif

dll00.c

#include <stdio.h>
#include "Python.h"
#define DLL0_EXPORTS
#include "dll00.h"

#define C_TAG "From C .dll"


int dll00Func00(double t, double delta, unsigned int size, const double *pIn, double *pOut) {
    int res = 0;
    printf("%s: in function\n", C_TAG);
    const int isInit = Py_IsInitialized();
    // Modify array calling Python functions
    if (!isInit) {
        printf("%s: initializing Python interpreter\n", C_TAG);
        Py_Initialize();
    }
    res = PyRun_SimpleString("print(\"From Python (within C .dll): test\")");
    for (unsigned  int i = 0; i < size; i++) {
        pOut[i] = pIn[i] * t + delta;
    }
    if (!isInit) {
        printf("%s: uninitializing Python interpreter\n", C_TAG);
        Py_Finalize();
    }
    return 0;
}

main00.c

#include <stdio.h>

#include "dll00.h"
#define SIZE 4


int main() {
    int res = 0;
    double in[SIZE] = { 1.0, 2.0, 3.0, 4.0 };
    double out[SIZE] = { 0 };
    res = dll00Func00(2, 0.5, SIZE, in, out);
    printf("Output array:\n");
    for (unsigned int i = 0; i < SIZE; i++) {
        printf("%.03f ", out[i]);
    }
    printf("\n");
    return 0;
}

code00.py

#!/usr/bin/env python

import sys
import ctypes as ct


DLL_NAME = "./dll00.dll"


def main(*argv):
    DblPtr = ct.POINTER(ct.c_double)
    size = 5
    DblArr = ct.c_double * size

    dll00 = ct.PyDLL(DLL_NAME)
    dll00Func00 = dll00.dll00Func00
    dll00Func00.argtypes = (ct.c_double, ct.c_double, ct.c_uint, DblPtr, DblPtr)
    dll00Func00.restype = ct.c_int

    in_arr = DblArr(*range(size))
    out_arr = DblArr()
    print("Output array:")
    for i in range(size):
        print("{:.3f}".format(out_arr[i]), end=" ")
    print("\n")
    res = dll00Func00(2, 2.5, size, in_arr, out_arr)
    print("Output array:")
    for i in range(size):
        print("{:.3f}".format(out_arr[i]), end=" ")
    print()



if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

Notes

  • Python中,使用([[间接)调用Python API函数]时使用ctypes.PyDLL
  • 。dll]中,使用[Python 3.Docs]: Initialization, Finalization, and Threads - int Py_IsInitialized()
      作为旁注,在
    • Py_Initialize
    • 的情况下,不需要if测试,因为Py_Initialize仅返回解释器是否已初始化(因此,为了一致性起见,我就把它留在那里了) ,但Py_Finalize则需要它,因为当您仍在Python中时,不想取消初始化解释器。因此Py_Initialize / Py_Finalize对在“引用计数”上不起作用(每个Py_Initialize调用都需要一个[[Py_Finalize
    一个)]
输出:

e:\Work\Dev\StackOverflow\q059937552>sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x64 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.19 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x64' [prompt]> dir /b code00.py dll00.c dll00.h main00.c [prompt]> cl /nologo /MD /DDLL /I"c:\Install\pc064\Python\Python\03.07.06\include" dll00.c /link /NOLOGO /DLL /OUT:dll00.dll /LIBPATH:"c:\Install\pc064\Python\Python\03.07.06\libs" dll00.c Creating library dll00.lib and object dll00.exp [prompt]> cl /nologo /MD /W0 main00.c /link /NOLOGO /OUT:main00_064.exe dll00.lib main00.c [prompt]> dir /b code00.py dll00.c dll00.dll dll00.exp dll00.h dll00.lib dll00.obj main00.c main00.obj main00_064.exe [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Output array: 0.000 0.000 0.000 0.000 0.000 From C .dll: in function From Python (within C .dll): test Output array: 2.500 4.500 6.500 8.500 10.500 Done. [prompt]> set PATH=%PATH%;c:\Install\pc064\Python\Python\03.07.06 [prompt]> main00_064.exe From C .dll: in function From C .dll: initializing Python interpreter From Python (within C .dll): test From C .dll: uninitializing Python interpreter Output array: 2.500 4.500 6.500 8.500

© www.soinside.com 2019 - 2024. All rights reserved.