【问题标题】:C++ OpenMP Tasks - passing by reference issueC++ OpenMP 任务 - 通过引用传递问题
【发布时间】:2015-01-09 22:56:29
【问题描述】:

我目前正在开发一个系统,在该系统中我读取超过约 2 亿条记录(行)的文件,因此我正在缓冲记录并使用 OpenMP 任务来管理每个批次,同时继续处理输入。缓冲区中的每条记录在work_on_data 中处理大约需要60μ,并且会生成一个字符串结果。为了避免关键区域,我为结果创建了一个向量,并通过地址将记录占位符(我插入到这个向量中)传递给 work_on_data 函数:

int i = 0;
string buffer[MAX_SIZE];
vector<string> task_results;

#pragma omp parallel shared(map_a, task_results), num_threads(X) 
#pragma omp single
{
    while (getline(fin, line) && !fin.eof())
    {
        buffer[i] = line;
        if (++i == MAX_SIZE)
        {
            string result = "";
            task_results.push_back(result);
#pragma omp task firstprivate(buffer)
            work_on_data(buffer, map_a, result);
            i = 0;
        }
    }
}

// eventually merge records in task_results

work_on_data 的末尾,传入的每个result 都不会是空字符串(如已初始化)。 但是,当合并结果时,每个结果仍然是一个空字符串。我可能在范围/寻址方面做了一些愚蠢的事情,但我不明白问题出在哪里。有什么想法吗?

提前致谢。

【问题讨论】:

    标签: c++ reference io parallel-processing openmp


    【解决方案1】:

    将某些东西推入向量会导致在向量内构造它的副本。因此,您的 work_on_data 函数不会获得对向量内字符串的引用,而是对 if 块内的字符串的引用。要解决此问题,您可以重写代码以使其访问 push_back 之后的最后一个元素,如下所示:

    if (++i == MAX_SIZE)
    {
        task_results.push_back("");
    #pragma omp task firstprivate(buffer)
        work_on_data(buffer, map_a, task_results.back());
        i = 0;
    }
    

    编辑

    我忘记了向量重新分配时的迭代器失效,另外对back() 的调用会导致竞争条件。使用(智能)指针(正如 cmets 所建议的那样)和专用计数器,这对我有用,没有段错误:

    vector<shared_ptr<string>> task_results;
    
    int ctr = 0
    ...
    if (++i == MAX_SIZE) {
        task_results.push_back(make_shared<string>());
    #pragma omp task firstprivate(buffer, ctr) 
        work_on_data(buffer, map_a, *task_results.back[ctr]);
        i = 0;
        ++ctr;
    
    }
    

    我认为back() 版本会出现段错误,因为该函数同时被许多不同的线程调用,并且如果主线程也设法达到push_back 之间的某个位置,那么线程将处理相同的数据。

    【讨论】:

    • 我假设如果在任务期间再次调用push_back 这不会导致问题?谢谢!我试试看。
    • 段错误。我相信这可能归结为push_back 是危险的,因为std::vector 不是线程安全的。鉴于任务的性质,不太确定如何解决这个问题!
    • @PidgeyBAWK 尝试使用vector&lt;string*&gt;,与string *result = new string()push_back(result),或与C++ 指针类等效。这样字符串将被正确传递。
    • @ElderBug 感谢您的评论,这是有道理的,我会试一试 - 是时候找到合适的 C++ 智能点了。我是否认为如果push_back 导致向量调整大小并重新分配(我不能提前依赖保留),这个内存地址将保持有效?
    • @PidgeyBAWK 是的,它会的。向量中的指针本身将被重新定位,但您的任务有该指针的副本,该指针仍将指向正确的字符串(向量仅管理它自己分配的内存)。
    猜你喜欢
    • 2017-10-09
    • 1970-01-01
    • 2015-08-09
    • 2011-03-14
    • 1970-01-01
    • 2018-02-13
    • 2014-08-02
    • 2011-01-17
    • 2012-09-06
    相关资源
    最近更新 更多