c++ - 尝试与 OpenMP 并行处理链表数据

标签 c++ openmp singly-linked-list

我正在尝试在 C++ 中与 OpenMP 并行处理链表数据。我对 OpenMP 很陌生,对 C++ 很生疏。我想做的是让几个线程打散链表,并输出特定范围内的节点数据。我不关心输出发生的顺序。如果我能让它正常工作,我想用对节点数据的一些实际处理来替换简单的输出。

我在互联网上找到了一些东西(包括这个网站上的一些问题),根据我的发现,我拼凑了一个这样的代码:

        #include <iostream>
        #include <omp.h>

        // various and sundry other stuff ...

        struct Node {
                int data;
                Node* next;
        };

        int main() {

            struct Node *newHead;
            struct Node *head = new Node;
            struct Node *currNode;
            int n;
            int tid;

            //create a bunch of Nodes in linked list with "data" ...

            // traverse the linked list:
            // examine data
            #pragma omp parallel private(tid)
            {
            currNode = head;
            tid=omp_get_thread_num();
            #pragma omp single
            {
            while (currNode) {
               #pragma omp task firstprivate(currNode)
               {
               cout << "Node data: " << currNode->data << " " << tid << "\n";
               } // end of pragma omp task
               currNode = currNode->next;
            } // end of while
            } //end of pragma omp single

            }  // end of pragma omp parallel


    // clean up etc. ...

    }  // end of main

所以我跑:

>: export OMP_NUM_THREADS=6
>: g++ -fopenmp ll_code.cpp
>: ./a.out

输出是:

Node data: 5 0
Node data: 10 0
Node data: 20 0
Node data: 30 0
Node data: 35 0
Node data: 40 0
Node data: 45 0
Node data: 50 0
Node data: 55 0
Node data: 60 0
Node data: 65 0
Node data: 70 0
Node data: 75 0

因此,tid 始终为 0。这意味着,除非我真的误解了什么,否则只有一个线程对链表执行任何操作,因此根本不会并行遍历链表。

当我去掉 single 时,代码因段错误而失败。我尝试将一些变量移入和移出 OpenMP 指令范围,但没有任何变化。更改线程数无效。如何让它发挥作用?

第二个问题:有些网站说 firstprivate(currNode) 是必需的,而其他网站说 currNode 默认是 firstprivate。谁是对的?

最佳答案

您当然可以使用多个线程遍历链表,但实际上它会比仅使用单个线程慢。

原因是,要知道节点 N != 0 的地址,您必须知道节点 N-1 的地址。

假设现在您有 N 个线程,每个线程负责“从 i 位置开始”。上面的段落暗示线程 i 将取决于线程 i-1 的结果,而线程 i-1 又将取决于线程 i-2< 的结果,等等。

无论如何,您最终得到的是串行遍历。但是现在,您还必须同步线程,而不仅仅是一个简单的 for,这使得事情本质上变慢了。

但是,如果您正在尝试执行一些可以从并行运行中获益的繁重处理,那么是的,您将采用正确的方法。您可以更改获取线程 ID 的方式:

#include <iostream>
#include <omp.h>

struct Node {
        int data;
        Node* next;
};

int main() {

    struct Node *head = new Node;
    struct Node *currNode = head;

    head->data = 0;
    for (int i=1;i<10;++i) {
        currNode->next = new Node;
        currNode = currNode->next;
        currNode->data = i;
    }

    // traverse the linked list:
    // examine data
    #pragma omp parallel
    {
        currNode = head;
        #pragma omp single
        {
            while (currNode) {
               #pragma omp task firstprivate(currNode)
               {
                   #pragma omp critical (cout)
                   std::cout << "Node data: " << currNode->data << " " << omp_get_thread_num() << "\n";
               }
               currNode = currNode->next;
            }
        }
    }
}

可能的输出:

Node data: 0 4
Node data: 6 4
Node data: 7 4
Node data: 8 4
Node data: 9 4
Node data: 1 3
Node data: 2 5
Node data: 3 2
Node data: 4 1
Node data: 5 0

See it live!

最后,对于更惯用的方法,请考虑使用 std::forward_list :

#include <forward_list>
#include <iostream>
#include <omp.h>

int main() {

    std::forward_list<int> list;
    for (int i=0;i<10;++i) list.push_front(i);

    #pragma omp parallel
    #pragma omp single
    for(auto data : list) {
       #pragma omp task firstprivate(data)
       #pragma omp critical (cout)
       std::cout << "Node data: " << data << " " << omp_get_thread_num() << "\n";
    }
}

关于c++ - 尝试与 OpenMP 并行处理链表数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49801820/

相关文章:

java - java将两个链表合并成新的链表

c++ - 函数中模板类的返回值不能去掉 "warning not all control paths return a value"

c++ - 从文件夹创建 zip 文件 - 在 C++ 中

gcc - 使用 GSL 和 OpenMP 编译

parallel-processing - 基于求和的 OpenMP

c - 单链表 : newNode function doesn't point to next Node

c++ - 计算两个数字之间差异的最短方法?

c++ - 如何在 Eclipse 项目中正确包含 Dlib?

multithreading - Prange 减慢 Cython 循环速度

c - 分段故障二叉树遍历