使用多个线程解析c ++字符串

时间:2013-06-25 12:37:57

标签: c++ parsing pthreads sstream

我已经将一个巨大的文件映射到char字符串中并从中创建了一个c ++字符串。我需要根据一个空格字符的分隔字符解析这个字符串,并将值存储在矩阵中。我可以从一个线程做到但我需要优化它。所以我使用多个线程来解析来自这个sstream的字符串并将其存储在矩阵中。虽然基于线程id,但我可以将解析后的数据同步存储到矩阵中但是我如何同步解析,因为任何线程都可以随时调度并解析字符串。这是我的代码

void* parseMappedString(void* args)
{
    char temp[BUFFSIZE];
    long int threadID = *((long int*)args);
    if (threadID  < 0)
        threadID = 0;

    for (int i = ((threadID) * 160); i < ((threadID+1) * 160); i++)
    {
        for (int j = 0; j < 4000; j++)
        {
            pthread_mutex_lock(&ParseMatrixMutex);
            if ((matrix_str.getline(temp,BUFFSIZE, ' ')) )
            {
                pthread_mutex_unlock(&ParseMatrixMutex);
                matrix[i][j] = parseFloat((temp));
            }
            else
            {
                pthread_mutex_unlock(&ParseMatrixMutex);
            }
        }
    }
}

void create_threads_for_parsing(void)
{
    long int i;

    for (i = 0; i < 5; i++)
        pthread_create(&Threads[i], NULL, parseMappedString, (void*)&i);
}

在代码中,如果您看到总共有五个线程,并且每个线程正在处理160 * 4000个元素。并且它们基于其线程ID存储,因此进入矩阵中的唯一位置。所以它是同步的方式。但getline可以在任何时候由任何线程完成,因此5号线程可以解析属于第一个线程的数据。我该如何避免这种情况?

我必须遵循因为我在args中接收1-4个threadids但从不接收0.它总是以一些垃圾负值而来,因此我不得不像这样硬编码。

if(threadID&lt; 0)     threadID = 0;

4 个答案:

答案 0 :(得分:1)

  

我已经将一个巨大的文件映射到char字符串并制作了一个c ++字符串

不要,std::string必须复制内存,因此你会失去性能提升mmap否则会得到你。只需将原始内存作为char数组

  

我可以从一个线程做到但我需要优化它

您确定多个线程优化它吗?你是否有资料并确认它绝对是CPU限制而不是I / O限制?


如果您确定要使用多个线程,我建议您这样做:

  1. 创建 N 个线程(这应该基于核心数量,然后根据测试结果进行调整)
  2. 将您的mmap'd区域划分为大小相等的 N
    • 你可以回顾一下&amp;最近到你的区块边界的新线
  3. 让每个帖子 n 创建自己的独立输出
  4. 之后合并所有输出

  5. 至于代码中的错误我试图说服你不要使用:你将(void*)&i作为你的参数传递给线程函数。这是一个指向create_threads_for_parsing末尾超出范围的自动局部的指针,所以当任何线程读取它时,它可能是随机垃圾。 即使它不是 random 垃圾(即,如果create_threads_for_parsing在返回之前加入所有线程,保持i在范围内),它将相同每个线程的指针

    为了安全地向每个线程传递一个不同的整数id,你应该为每个线程分配一个不同的整数,并传递它的地址。这可能是intptr_t或其他问题。

答案 1 :(得分:0)

std::string::getline不是线程安全的,您不能使用来自不同线程的getline()

您需要使用strncopy(c-style)访问内存中原始字符串数据中的已知位置

strncopy(matrix_str.c_str(), temp, 4000);

或使用substring-function(C ++风格)

std::string piece = matrix_str.substr(i,4000)

编辑:如果您的matrix_str不是std::string而是std::sstream对象,则无法按顺序访问流。你的问题在这方面有点模糊......

答案 2 :(得分:0)

代码几乎完全是互斥的 - 因此使用线程毫无意义。

腭化的想法是允许实际上同时完成工作。为此,您应减少数据共享,理想情况下为零。

就像将大字符串分成前面的4个部分并将其发布到线程一样,这样他们就可以读取和处理它,将结果放在它们的专属位置。如果没有共享单元格,输出可以转到矩阵,但要注意false sharing仍可能破坏性能。

答案 3 :(得分:0)

在奇怪的0 ID部分:我认为发布的代码只是演示,但你可能会像字面意思那样。

在离开函数create_threads_for_parsing之前,必须加入所有线程。目前您传递给指向其中的局部变量的线程指针。

更糟糕的是,变量是共享的,因此你有一个竞争条件。你做了类似的事情:

static const int ids = {0, 1, 2, 3, 4};

并将指针传递给循环中的正确单元格。