尝试与OpenMP并行处理链表数据 我试图在C++中并行处理OpenMP的链表数据。我对OpenMP非常陌生,而且C++也相当粗糙。我想做的是让几个线程分解链表,并输出特定范围内节点的数据。我不关心输出发生的顺序。如果我能做到这一点,我想用节点数据的一些实际处理来代替简单的输出

尝试与OpenMP并行处理链表数据 我试图在C++中并行处理OpenMP的链表数据。我对OpenMP非常陌生,而且C++也相当粗糙。我想做的是让几个线程分解链表,并输出特定范围内节点的数据。我不关心输出发生的顺序。如果我能做到这一点,我想用节点数据的一些实际处理来代替简单的输出,c++,openmp,singly-linked-list,C++,Openmp,Singly Linked List,我在互联网上找到了一些东西(包括这个网站上的一些问题),根据我的发现,我拼凑了一个如下代码: #include <iostream> #include <omp.h> // various and sundry other stuff ... struct Node { int data; Node* next; };

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

        #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
输出为:

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。这意味着,除非我真的误解了什么,只有一个线程对链表做了任何事情,所以链表根本没有被并行遍历

当我去掉
单个
时,代码会因seg故障而失败。我尝试过在OpenMP指令作用域内外移动一些变量,但没有任何更改。更改线程数无效。如何才能使其发挥作用


第二个问题:一些网站说
firstprivate(currNode)
是必要的,而另一些网站说
currNode
默认为
firstprivate
。谁是对的?

您当然可以使用多个线程遍历链接列表,但实际上这比仅使用一个线程要慢

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

假设现在有
N
线程,每个线程负责“从
i
位置开始”。上面的段落意味着线程
i
将取决于线程
i-1
的结果,而线程
i-2
的结果反过来又取决于线程
i-2
的结果,依此类推

不管怎样,最终的结果是一个串行遍历。但是现在,你也必须同步线程,而不仅仅是对
进行简单的
,这会让事情变得更慢

但是,如果您正试图进行一些繁重的处理,这将从并行运行中获益,那么是的,您将采用正确的方法。您只需更改获取线程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;
            }
        }
    }
}
最后,对于一个更习惯的方法,考虑使用A:

#包括
#包括
#包括
int main(){
std::转发列表;

for(int i=0;iA链表是一种天生的串行结构,因此很难看出多线程可以帮助遍历一个。@NeilButterworth我理解你的观点,但有很多网站都说这是可能的,如果我能让它工作的话!)关键是要强调我在问题中所说的,我不在乎输出的顺序。因此每个线程可以从不同的位置开始,只进行“局部”遍历,直到到达下一个线程开始的位置(或列表的末尾)。“因此每个线程可以从不同的位置开始”-它怎么能在不遍历列表的情况下找到开始的位置?@NeilButterworth,我完全明白你的意思。不过,有很多人的想法不同。例如,请参见开始第127页和第142页。你既没有多个任务,也没有OpenMP可以并行运行的循环。非常感谢,但有些事情确实很重要奇怪。我直接复制并粘贴了你的第一个代码并运行了它。我仍然在每次输出时获得相同的线程。出于某种原因,每次运行时都不是线程0。但在一次运行中都是0,然后在下一次运行中都是4,等等。我添加了一个omp_get_num_threads()为了确保我实际运行的线程不止一个,而且看起来还可以。谢谢你的帮助。我不知道发生了什么。我是否遇到了一些奇怪的系统问题?@bob.sacamento没有任何东西可以保证使用多个线程(为什么要这样做?你只想尽快完成处理,对吗?)。如果您的处理速度太快,则可能只是在每次迭代中重复使用同一个线程。在本代码段中可能确实如此,因为所做的只是将一个整数打印到标准输出。请尝试使用一些实际处理来测试这一点,这可能需要一些时间才能完成。@CássioRenan非常感谢您的持续帮助。我添加了一些虚拟处理,每个节点需要花费大量的时间(~0.25秒)。线程并行性没有变化。这听起来合理吗?再次感谢。@CássioRenan OK。切换到另一个系统。看到了清晰的并行性。所以你是对的,我接受你的答案。谢谢!
#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
#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";
    }
}