【问题标题】:Variables do not have the same value when passed into shared library functions变量在传递到共享库函数时没有相同的值
【发布时间】:2013-10-02 13:29:47
【问题描述】:

我开发了一些需要集成到现有 C 代码中以更新其功能的功能。 为了使调用新函数尽可能简单,我定义了一个容器结构,其中包含我需要的所有指针和数据,例如

typedef struct parameters
{
    double time;
    int num_sp;
    int num_nodes;
    int dielCount;
    double meshbounds[6];
} Params;

typedef struct FGM_Container
{
    dev_nodes *d_nodes;
    dev_nodes *h_nodes;
    dev_species *d_sp;
    dp_tree *octree;
    dp_params *dp_pars;
    dev_params *d_p;
    Params           p;     /* Parameters */
    Nodes           *n;     /* nodes array */
    int free_dev_flag;
    double guard_range;
    int max_octree_depth;
} fgm_container;

我将我的函数编译成一个名为 FGM 的共享库(.so 因为我在 Linux 中工作),提供了一个标头,其中包含要从原始代码调用的函数的原型,并成功地重建了整个项目。但是,当执行进入我的函数时,传递给它们的变量似乎不会保留相同的值。这是一个非常简单的示例,之前和之后的代码更复杂,但这代表了我正在观察的行为:

int fgm_init(fgm_container *fgmc, int verbose);


int main()
{
    int fgm_ok = 0;
    int free_dev_flag;
    double guard_range = 0;
    int max_octree_depth = 5;

    Params p;
    fgm_container fgmc;

    //Set parameters
    p.time = 0;
    p.num_sp = 2;
    p.num_nodes = 500;
    p.dielCount = 1;
    p.meshbounds[0] = -0.019;
    p.meshbounds[1] =  0.0475;
    p.meshbounds[2] = -0.045;
    p.meshbounds[3] =  0.032;
    p.meshbounds[4] = -0.027;
    p.meshbounds[5] =  0.010;

    //Fill FGM container
    fgmc.p = p;
    fgmc.guard_range = guard_range;
    fgmc.max_octree_depth = max_octree_depth;

    //Print original data
    printf("Original data:\n");
    printf("dielCount: %d\n", fgmc.p.dielCount);
    printf("species: %d\n", fgmc.p.num_sp);
    printf("meshb: %lf %lf\n", fgmc.p.meshbounds[0], fgmc.p.meshbounds[1]);


    //Initialize FGM library
    fgm_ok = fgm_init(&fgmc, 2);

    if (fgm_ok != 0)
    {
        printf("FGM initialization failed. Exiting.\n");
        exit(-1);
    }

    return 0;
}


int fgm_init(fgm_container *fgmc, int verbose)
{
    int ok_flag=0;

    //Extract data from FGM container
    Params p = fgmc->p;
    double guard_range = fgmc->guard_range;
    int max_octree_depth = fgmc->max_octree_depth;


    if (verbose > 0) printf("FGM: Initializing...\n");
    printf("species: %d\n", p.num_sp);
    printf("meshb: %lf %lf\n", p.meshbounds[0], p.meshbounds[1]);
    printf("dielCount: %d\n", p.dielCount);
    getchar();  


    //Proceed with other initialization steps...

    return ok_flag;
}

这段代码在我的屏幕上输出

Original data:
dielCount: 1
species: 2
meshb: -0.019000 0.047500

FGM: Initializing...
dielCount: 28203712
species: 2
meshb: 0.000000 0.000000
dielcount: 28203712

每次我启动代码时,dielCount 的值都会发生变化,就好像它是一个未初始化的变量一样。由于在各种 malloc 函数中使用了各种参数,所以事情很快就会失控,我开始出现内存不足错误等等。 此外,如果我尝试将参数结构本身按值传递给初始化函数,我也会得到相同的结果,即:

int fgm_init(fgm_container *fgmc, Params p, int verbose);


int main()
{
    // Same steps as before...

    //Initialize FGM library
    fgm_ok = fgm_init(&fgmc, p, 2);

    if (fgm_ok != 0)
    {
        printf("FGM initialization failed. Exiting.\n");
        exit(-1);
    }

    return 0;
}


int fgm_init(fgm_container *fgmc, Params p, int verbose)
{
    int ok_flag=0;

    if (verbose > 0) printf("FGM: Initializing...\n");
    printf("species: %d\n", p.num_sp);
    printf("meshb: %lf %lf\n", p.meshbounds[0], p.meshbounds[1]);
    printf("dielCount: %d\n", p.dielCount);
    getchar();  


    //Proceed with other initialization steps...

    return ok_flag;
}

我想指出,共享库已通过单独的小测试验证正确执行,然后再集成到目标项目(相当大)中。

这个错误让我忙了好几个小时,因为我试图弄明白,显然我遗漏了一些东西。 关于使用共享库有什么我应该知道的,因为这是我第一次自己创建一个?这可能与编译有关吗,因为原始项目是用 C 编译器编译的,而我的库是用 NVIDIA NVCC 编译器编译的(因为我也使用了一些 CUDA 调用,但它们是在麻烦的部分之后出现的),这是一个 C++ 编译器主机代码部分? 感谢您提供的任何见解。

【问题讨论】:

  • “我想指出,共享库在被集成到目标项目(相当大)之前,已经通过单独但小的测试验证可以正确执行。”你不能参加这个测试程序并找出有什么不同吗?至少使用调试器仔细运行初始化并查看何时出现问题。它将帮助您准确找到正在发生的事情。另外 - 您确定它正在加载正确版本的库吗?
  • (只是一个猜测),您用于编译 2 个库的头文件是否相同?例如,如果由于某些原因,您使用的头文件与struct parameters 的定义不同,我认为您可能会遇到这样的问题。
  • fgm_init 函数中的printfs 从p.XXXX 更改为fgmc->p.XXXX 时的输出是什么?
  • 我怀疑主机编译器和 nvcc 之间存在不同的结构填充和大小问题。特别是 meshbounds 不会与没有填充的 double 边界对齐。由于主机和设备代码之间的struct 可移植性,以及所有数据自然对齐的设备端要求,nvcc 将添加填充以将meshbounds 对齐到double 边界。尝试使用-malign-double 构建您的库代码。

标签: c++ c cuda shared-libraries


【解决方案1】:

您是否检查过 .so 文件中的符号(使用 nm 或类似工具)? C++ 编译器可能会破坏名称,从而导致您的应用程序中发生奇怪的事情。

在结构周围添加extern "C" 可能会解决您的问题。 例如:

extern "C" {
    typedef struct parameters
    {
        double time;
        int num_sp;
        int num_nodes;
        int dielCount;
        double meshbounds[6];
    } Params;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 2014-07-08
    • 2017-11-19
    • 1970-01-01
    相关资源
    最近更新 更多