尝试与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";
}
}