C++에서 OpenMP 병렬 처리 라이브러리를 배우고 있습니다. 기본적인 개념을 가지고 있고 링크 된 목록 큐를 구현하여 지식을 테스트하려고했습니다. 여러 스레드에서 큐를 소비하려고했습니다.다중 스레드에서 연결 목록 대기열 사용
여기서 도전은 동일한 노드를 두 번 사용하지 않는 것입니다. 그래서 스레드간에 큐를 공유하는 것을 고려하고 있었지만 한 번에 하나의 스레드 만 업데이트 (큐의 다음 노드로 이동) 할 수있었습니다. 이 목적을 위해 나는 치명적이거나 잠금을 사용할 수 있습니다. 그러나, 그들을 사용하지 않고; 어쨌든, 그것은 완벽하게 작동하는 것 같습니다. 경쟁 조건이 발생하지 않았습니다.
#include <iostream>
#include <omp.h>
#include <zconf.h>
struct Node {
int data;
struct Node* next = NULL;
Node() {}
Node(int data) {
this->data = data;
}
Node(int data, Node* node) {
this->data = data;
this->next = node;
}
};
void processNode(Node *pNode);
struct Queue {
Node *head = NULL, *tail = NULL;
Queue& add(int data) {
add(new Node(data));
return *this;
}
void add(Node *node) {
if (head == NULL) {
head = node;
tail = node;
} else {
tail->next = node;
tail = node;
}
}
Node* remove() {
Node *node;
node = head;
if (head != NULL)
head = head->next;
return node;
}
};
int main() {
srand(12);
Queue queue;
for (int i = 0; i < 6; ++i) {
queue.add(i);
}
double timer_started = omp_get_wtime();
omp_set_num_threads(3);
#pragma omp parallel
{
Node *n;
while ((n = queue.remove()) != NULL) {
double started = omp_get_wtime();
processNode(n);
double elapsed = omp_get_wtime() - started;
printf("Thread id: %d data: %d, took: %f \n", omp_get_thread_num(), n->data, elapsed);
}
}
double elapsed = omp_get_wtime() - timer_started;
std::cout << "end. took " << elapsed << " in total " << std::endl;
return 0;
}
void processNode(Node *node) {
int r = rand() % 3 + 1; // between 1 and 3
sleep(r);
}
출력은 다음과 같습니다 : I 스레드 여러 번 다른 번호로이를 실행했습니다
Thread id: 0 data: 0, took: 1.000136
Thread id: 2 data: 2, took: 1.000127
Thread id: 2 data: 4, took: 1.000208
Thread id: 1 data: 1, took: 3.001371
Thread id: 0 data: 3, took: 2.001041
Thread id: 2 data: 5, took: 2.004960
end. took 4.00583 in total
. 그러나 나는 어떤 경쟁 조건이나 잘못된 것을 얻을 수 없었다. 두 개의 다른 스레드가 '제거'를 호출하고 단일 노드를 두 번 처리하는 것이 가능하다고 생각했습니다. 그러나 그것은 일어나지 않았다. 왜?
https://github.com/muatik/openmp-examples/blob/master/linkedlist/main.cpp
결과로 기대되는 것은 무엇입니까? 큐 처리 중에 변수를 수정하거나 다시 쓰는 것 같지 않습니다. 아무 것도 수정하지 않으면 스레드가 활성화되는 순서를 제외하고 매번 같은 결과를 얻을 수 있습니다. 제어하거나 예측할 수는 없습니다. 노드에 액세스하는 순서에 따라 어떤 종류의 작업을 수행하면 다른 결과가 발생할 수 있습니다. 또는 모든 잠금을 사용하지 않고 모든 스레드가 동일한 변수에 쓰면 잠재적으로 경쟁 조건이 발생할 수 있습니다. 지금 당장 미안하다고 생각할 수 있습니다. – Jarak
스레드가 스레드간에 공유되는 큐를 사용한다고 생각합니다. 그들은 큐의'remove' 메소드를 호출하고 큐는 그 헤드 포인터를 다음 노드로 변경합니다. 두 스레드가 동시에 remove()를 호출하고 같은 노드를받을 수 있습니까? – Muatik
예 가능합니다. 두 스레드가 제거를 마칠 수 있기 전에 두 스레드가'node = head; '를 완료하는 것을 막을 수있는 방법은 없습니다. 지금까지의 모습에 따라 운이 좋았거나 불행했습니다. 더 긴 큐로 시도하십시오. – user4581301