You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含mpfr_t的自定义MPI结构体传输问题求助

MPFR结合MPI传输自定义结构体的错误修复

问题背景

将程序迁移到任意精度计算(使用MPFR库)时,原有的自定义MPI结构体需要替换为包含mpfr_t类型的字段。最初尝试直接用MPI_Type_create_struct定义结构体类型,但因mpfr_t的精度未固定,MPI无法确定其实际大小,导致传输失败。

后续改用MPI_Pack/MPI_Unpack处理,能正常传输int类型字段,但mpfr_t变量的导出、发送、接收、导入出现问题:前3个mpfr_t变量导入后为垃圾值,最后一个触发SIGABRT错误,断言信息为get_str.c:157: MPFR assertion failed: size_s1 >= m。

最初尝试的错误代码

typedef struct job_s {
    int f;
    mpfr_t l,t,r,b;
} jobs;

MPI_Datatype MPI_JOBS_TYPE;
MPI_Type_create_struct(
    5,
    (int []) {1, sizeof(mpfr_t), sizeof(mpfr_t), sizeof(mpfr_t), sizeof(mpfr_t)},
    (MPI_Datatype []) {offsetof(jobs,f), offsetof(jobs,l), offsetof(jobs,t), offsetof(jobs,r), offsetof(jobs, b)},
    (MPI_Datatype []) {MPI_INT, MPI_BYTE, MPI_BYTE, MPI_BYTE, MPI_BYTE},
    &MPI_JOBS_TYPE
);

MPI_Type_commit(&MPI_JOBS_TYPE);

出错的发送端代码

char * mpfr_buf;
size_t mpfr_buf_size;
char buf [3000];
pos = 0;
MPI_Pack(&f, 1, MPI_INT, buf, 3000, &pos, MPI_COMM_WORLD);

stream = open_memstream(&mpfr_buf, &mpfr_buf_size);
for(i = 0; i < 4; ++i)
    mpfr_fpif_export(stream, bounds[i]);
MPI_Pack(stream, 3000-sizeof(int), MPI_BYTE, buf, 3000, &pos, MPI_COMM_WORLD);

print_bounds(bounds, "s");

MPI_Send(buf, pos, MPI_PACKED, reqRank, 0, MPI_COMM_WORLD);

fclose(stream);
f += 1;

出错的接收端代码

pos = 0;
char buf [3000];
MPI_Recv(buf, 3000, MPI_PACKED, PARENT, 0, MPI_COMM_WORLD, &status);
int msgSize = 0;
MPI_Get_count(&status, MPI_BYTE, &msgSize);
printf("msg size %d\n", msgSize);
MPI_Unpack(buf, 3000, &pos, &f, 1, MPI_INT, MPI_COMM_WORLD);
printf("Worker %d recived frame %d\n", rank, f);

char streambuf [3000];
MPI_Unpack(buf, 3000, &pos, streambuf, msgSize - pos, MPI_BYTE, MPI_COMM_WORLD);
stream = fmemopen(streambuf, 3000, "r");
for(i = 0; i < 4; ++i){
    mpfr_fpif_import(bounds[i], stream);
}
fclose(stream);

错误原因及修复方案

核心错误点

  1. 发送端打包对象错误:试图打包文件流指针stream而非实际导出的MPFR数据缓冲区mpfr_buf,且未关闭流就获取数据大小,导致mpfr_buf_size不准确。
  2. 接收端消息大小获取错误:MPI_Get_count使用MPI_BYTE类型,而发送的是MPI_PACKED类型,导致消息大小计算有误。
  3. 解包缓冲区范围错误:MPI_Unpack传入的总缓冲区大小为固定的3000,而非实际接收的msgSize,可能读取垃圾数据。
  4. 内存流初始化错误:fmemopen使用固定长度3000,而非实际MPFR数据长度,导致MPFR解析时读到无效数据触发断言。

修复后的发送端代码

char *mpfr_buf = NULL;
size_t mpfr_buf_size = 0;
char buf[3000];
int pos = 0;

// 打包int类型的f字段
MPI_Pack(&f, 1, MPI_INT, buf, 3000, &pos, MPI_COMM_WORLD);

// 将MPFR变量导出到内存流
FILE *stream = open_memstream(&mpfr_buf, &mpfr_buf_size);
if (!stream) {
    perror("open_memstream failed");
    exit(EXIT_FAILURE);
}
for (int i = 0; i < 4; ++i) {
    if (mpfr_fpif_export(stream, bounds[i]) != 0) {
        perror("mpfr_fpif_export failed");
        fclose(stream);
        free(mpfr_buf);
        exit(EXIT_FAILURE);
    }
}
// 关闭流后才能确保mpfr_buf_size是最终的实际数据大小
fclose(stream);

// 打包MPFR导出的实际数据
MPI_Pack(mpfr_buf, mpfr_buf_size, MPI_BYTE, buf, 3000, &pos, MPI_COMM_WORLD);

// 发送打包后的缓冲区
MPI_Send(buf, pos, MPI_PACKED, reqRank, 0, MPI_COMM_WORLD);

// 释放内存流分配的缓冲区
free(mpfr_buf);
f += 1;

修复后的接收端代码

int pos = 0;
char buf[3000];
MPI_Status status;

// 接收打包后的完整数据
MPI_Recv(buf, 3000, MPI_PACKED, PARENT, 0, MPI_COMM_WORLD, &status);
int msgSize = 0;
// 使用MPI_PACKED类型获取正确的消息大小
MPI_Get_count(&status, MPI_PACKED, &msgSize);
printf("msg size %d\n", msgSize);

// 解包int类型的f字段,传入实际消息大小作为缓冲区总长度
MPI_Unpack(buf, msgSize, &pos, &f, 1, MPI_INT, MPI_COMM_WORLD);
printf("Worker %d received frame %d\n", rank, f);

// 计算MPFR数据的实际长度
int mpfr_data_len = msgSize - pos;
char streambuf[3000];
// 解包MPFR数据,使用实际消息大小作为缓冲区总长度
MPI_Unpack(buf, msgSize, &pos, streambuf, mpfr_data_len, MPI_BYTE, MPI_COMM_WORLD);

// 以实际MPFR数据长度打开内存流,避免读取垃圾数据
FILE *stream = fmemopen(streambuf, mpfr_data_len, "r");
if (!stream) {
    perror("fmemopen failed");
    exit(EXIT_FAILURE);
}
for (int i = 0; i < 4; ++i) {
    if (mpfr_fpif_import(bounds[i], stream) != 0) {
        perror("mpfr_fpif_import failed");
        fclose(stream);
        exit(EXIT_FAILURE);
    }
}
fclose(stream);

内容的提问来源于stack exchange,提问作者Lucian Chauvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:24:50