【问题标题】:Python kernel crashing when calling shared C++ function调用共享 C++ 函数时 Python 内核崩溃
【发布时间】:2017-09-04 11:27:01
【问题描述】:

我是 C++ 新手,如有任何“愚蠢”的错误,我深表歉意。

我在 C++ 中创建了一个共享对象,用于 Python。但是,当我尝试在 Python 中调用此函数时,内核崩溃了。

C++文件如下:

#include <cmath>
#include <iostream>
#include <list>
#include <vector>

using namespace std;

extern "C" 
{
    vector<int> cplusplus(int n=3,int maximum=1000)
    {          
        int i,j,order,m,i1,i2,mag;
        vector<int> output(0);

        i=1;
        j=0;

        while (i/maximum<=1)
        {
            i=10*i;
            j=j+1;
        } 

        m=j-1;

        for (i1=1; i1<m+2; i1++)
        {
            mag=pow(10,(i1-1));
            i=0;

            while (i+mag*(n+1)<=maximum)
            {
                for (i2=i+mag*n; i2<i+mag*(n+1); i2++)
                {
                    output.push_back(i2-1);
                }
                i=i+10*mag;
            } 

            if(i+mag*(n+1)>maximum)
            {
                for (i2=i+mag*n; i2<maximum+1; i2++)
                {
                    output.push_back(i2-1);
                }   
            }
        } 

        return output;
    }
}

我使用以下方法创建 .so 文件:

g++ -shared -o cplusplus.so cplusplus.cpp

我使用 Python 调用 C++ 函数:

import ctypes

cpp=ctypes.cdll.LoadLibrary('/Users/.../cplusplus.so')
print cpp.cplusplus(n=3,maximum=1000)

该函数在正确返回时应返回一个包含 1 到 1000 之间的所有数字的向量,其中包含一个 3(即 3、13、23、30、31、...)。然而,目前 Python 内核崩溃了。

我想这与我使用向量或 C++ 文件中的内存泄漏有关。

提前感谢您的帮助!

【问题讨论】:

  • 这是ctypes 而不是cpptypesctypes 无法处理 vector&lt;int&gt;。您必须具有 C 数据类型。

标签: python c++ ctypes


【解决方案1】:

ctypes 不理解 C++ 类型,所以这里是一个在函数接口中只使用 C 类型的函数版本。结果缓冲区必须预先分配,并且通过地址传入的元素数量。该函数使用计算向量的长度更新元素的数量,如果可以将这些元素复制到结果缓冲区中,则返回 1(成功),否则返回 0(失败)。

请注意,代码算法不正确并返回错误答案,但 ctypes 有效。

#include <cmath>
#include <iostream>
#include <list>
#include <vector>
using namespace std;

extern "C"
{
    __declspec(dllexport) int cplusplus(int n, int maximum, int* result, size_t* pLength)
    {
        int i, j, order, m, i1, i2, mag;
        vector<int> output(0);

        i = 1;
        j = 0;

        while(i / maximum <= 1)
        {
            i = 10 * i;
            j = j + 1;
        }

        m = j - 1;

        for(i1 = 1; i1 < m + 2; i1++)
        {
            mag = pow(10, (i1 - 1));
            i = 0;

            while(i + mag * (n + 1) <= maximum)
            {
                for(i2 = i + mag * n; i2 < i + mag * (n + 1); i2++)
                    output.push_back(i2 - 1);

                i = i + 10 * mag;
            }

            if(i + mag * (n + 1) > maximum)
            {
                for(i2 = i + mag * n; i2 < maximum + 1; i2++)
                    output.push_back(i2 - 1);
            }
        }

        if(output.size() > *pLength)
        {
            *pLength = output.size();
            return 0; // fail
        }

        *pLength = output.size();
        memcpy(result, output.data(), output.size() * sizeof(int));
        return 1; // success
    }
}
>>> from ctypes import *
>>> lib = CDLL('test')
>>> lib.cplusplus.argtypes = c_int,c_int,POINTER(c_int),POINTER(c_size_t)
>>> lib.cplusplus.restype = c_int
>>> arr = (c_int * 1000)()
>>> size = c_size_t(1000)
>>> lib.cplusplus(3,1000,arr,byref(size))
1
>>> size
c_ulonglong(300)
>>> list(arr[:size.value])
[2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, 222, 232, 242, 252,
262, 272, 282, 292, 302, 312, 322, 332, 342, 352, 362, 372, 382, 392, 402, 412, 422, 432, 442, 452, 462, 472, 482, 492,
502, 512, 522, 532, 542, 552, 562, 572, 582, 592, 602, 612, 622, 632, 642, 652, 662, 672, 682, 692, 702, 712, 722, 732,
742, 752, 762, 772, 782, 792, 802, 812, 822, 832, 842, 852, 862, 872, 882, 892, 902, 912, 922, 932, 942, 952, 962, 972,
982, 992, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 229, 230, 231, 232,
233, 234, 235, 236, 237, 238, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 429, 430, 431, 432, 433, 434, 435, 436,
437, 438, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 729, 730,
731, 732, 733, 734, 735, 736, 737, 738, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 929, 930, 931, 932, 933, 934,
935, 936, 937, 938, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366,
367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390,
391, 392, 393, 394, 395, 396, 397, 398]
>>> size = c_size_t(200) # too small
>>> lib.cplusplus(3,1000,arr,byref(size))
0
>>> size
c_ulonglong(300)

【讨论】:

  • 非常感谢!算法中的错误语句是output_push.back(i2-1)。它应该是output_push.back(i2)
【解决方案2】:

我想知道 n 和最大值是否是实际变量。试试看:

Print cpp.cplusplus ()

尝试构建一个在 C++ 中显示矢量的方法。这样您就不会混合打印语言方法。

【讨论】:

  • 恐怕内核仍然使用这个崩溃。
【解决方案3】:

你需要告诉python你的函数的输入和返回类型是什么Docs。我很确定 std::vector 不是选项的一部分,这些选项在文档中列出。

这不是最快的最佳实践选项 我开始做的是将您的输入序列化为 json,并将它们作为 char_p 传递给共享库,然后将它们转换为 c++,并返回另一个 char_p ......但这当然不是最快或最好的选项。

(如果您确实正确定义了类型,请编辑您的帖子,我将删除此答案)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-20
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多