【问题标题】:std::vector as input buffer for MPI nonblocking functionsstd::vector 作为 MPI 非阻塞函数的输入缓冲区
【发布时间】:2018-07-13 09:50:12
【问题描述】:

TLDR:如果您的非阻塞 MPI 对等或 RMA 函数的输入缓冲区是一个向量,那么在某些时候指向底层元素的指针将无效(在向量插入时),导致如果通信操作未完成,内存损坏问题。

考虑这个函数,我必须将输入数据复制到一个向量中,然后再将其传递给MPI_Issend(或任何非阻塞发送):

    void TaggedIssend(int tag, int target, int count, const long* data)
    {
        // data
        const long msgq_size = msgQ_data_.size();
        for (int i = 0; i < count; i++)
            msgQ_data_.push_back(data[i]);

        // request
        const long req_size = msgQ_reqs_.size();
        msgQ_reqs_.push_back(MPI_REQUEST_NULL);

        MPI_Issend(&msgQ_data_[msgq_size], count, MPI_LONG, 
                target, tag, comm_, &msgQ_reqs_[req_size]);
    }

在某一时刻,msgQ_data_msgQ_reqs_ 将被移动(复制到新位置),此时如果发送未完成,则程序将崩溃(段错误会出现在看似奇怪的地方, 和 MPI_Request 对象在测试时可能会变为无效,仅举几例)。尽管我在这个特定问题中使用了std::vector,但动态调整数组大小也会出现同样的问题。这就是为什么 MPI 通信函数的输入缓冲区类型是const void*

问题:我很想知道安全地使用动态调整大小数组作为 MPI 非阻塞函数的输入缓冲区的技术。我目前正在将传出数据推送到固定大小的缓冲区中,当它已满时,我会一次性发出所有发送,并在重新使用缓冲区之前完成它们。任何人都可以提出更好的选择吗? 我在这里使用MPI_Issend 的原因是因为我的发送发生在while 循环中,我可以测试所有发送以完成通信(测试与MPI_Issend 关联的请求将仅在发布匹配的接收时返回true ),并用它来跳出循环。

【问题讨论】:

  • 标题有点误导,这种行为是意料之中的,这不是std::vector的错。我认为更自然的方法是使用从请求到数据向量的映射。
  • 是的,这是程序的产物,不是std::vector,这就是我写can be的原因。
  • MPI 标准规定,在非阻塞发送完成之前,不能修改发送缓冲区(例如,您的应用程序 MPI_Wait()MPI_Test())。否则,任何事情都可能发生……从某种意义上说,该标题具有误导性,它暗示了对标准的误解,而不是真正的问题。
  • 同意,为避免更多混淆,我编辑了标题并稍微澄清了问题。

标签: c++ vector mpi


【解决方案1】:

我很想知道安全地使用动态调整大小的数组作为 MPI 非阻塞函数的输入缓冲区的技术。

使用std::vector::reserve 分配足够的内存空间。然后,如果您将push_back 放入那个vector,则保证在保留容量未满之前不会重新分配。这个解决方案有点脆弱,但如果您提前知道最大矢量大小,它就会起作用。

或者,您也可以使用MPI_Bsend 发送,例如,使用一些递增的tag 参数,然后将此标签发回以测试是否已收到数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    相关资源
    最近更新 更多