pthread 관련하여 특정 스레드가 수행이 안되는 문제점
글쓴이: lv-99 / 작성시간: 금, 2021/05/14 - 1:42오전
스레드 수가 4개라고 가정하고 아래와 같은 코드를 돌리면 threads[0]을 제외하고 threads[1]부터 threads[3]까지만 수행이 되는 것 같습니다. threads[0]이 정상적으로 작동하려면 어떻게 해야하나요? 도저히 모르겠어서 질문 올립니다. 제가 무엇을 잘못하고 있나요?
pthread_create의 인자로는 구조체를 만들어 넘겨주었습니다.
예상 출력 결과로는
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
에서
1 0 0 0 0
1 2 0 0 0
1 2 3 0 0
1 2 3 4 0
1 2 3 4 5
이런 출력 결과를 원했지만 threads[0]이 정상 작동하지 않아서
1 2 3 4 5
1 2 0 0 0
1 2 3 0 0
1 2 3 4 0
1 2 3 4 5
이런 결과가 출력이 됩니다
아래는 전체 소스코드이고,
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <time.h> #include <sys/shm.h> #include <sys/mman.h> #include <sys/stat.h> #include <pthread.h> #include <assert.h> typedef struct arr { int q; //현 스레드 float a; float b; float x; }ARR; int n = 5; //배열의 크기 int tnum = 4; //총 스레드 수 int i = 0; pthread_barrier_t barrier; int start2(int n, int tnum, int q, int i) { int m = i; int r = m % tnum; int blockStart; if (q < r) { blockStart = (m / tnum + 1) * q; } else if (q >= r) { blockStart = (m / tnum + 1) * r + (m / tnum) * (q - r); } } int end2(int n, int tnum, int q, int i) { int m = i; int r = m % tnum; int blockEnd; if (q < r) { blockEnd = (m / tnum + 1) * (q + 1) - 1; } else if (q >= r) { blockEnd = (m / tnum + 1) * r + (m / tnum) * (q - r + 1) - 1; } return blockEnd; } void* parBackSubstitution(void* ary); int main() { pthread_t threads[tnum]; int rc; pthread_barrier_init(&barrier, NULL, tnum + 1); //구조체에 값 부여 ARR* ary = (ARR*)malloc(sizeof(ARR) * (5 * 5)); for (i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { ary[(i * 5) + j].a = j+1; } } for (i = 0; i < 5; i++) { ary[i].b = 1; } //계산 for (i = n - 1; i >= 0; i--) { ary[i].x = ary[i].b / ary[i * n + i].a; for (int q = 0; q < tnum; q++) { ary[0].q = q; //구조체에 현 스레드 넘버 넣음 rc = pthread_create(&threads[q], NULL, parBackSubstitution, ary); assert(rc == 0); } pthread_barrier_wait(&barrier); } for (int q = 0; q < tnum; q++) { pthread_join(threads[q], NULL); assert(rc == 0); } //출력 부분 for (i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("%f ", ary[i * n + j].a); } printf("\n"); } printf("\n"); for (int j = 0; j < n; j++) { printf("%f ", ary[j].b); } printf("\n"); free(ary); pthread_exit(NULL); pthread_barrier_destroy(&barrier); } void* parBackSubstitution(void* ary) { ARR* ar = (ARR*)ary; int q = ar[0].q; for (int j = end2(n, tnum, q, i); j >= start2(n, tnum, q, i); j--) { //병렬화가 되어야 하는 부분 ar[j * n + i].a = 0; } ary = ar; pthread_barrier_wait(&barrier); }
아래가 pthread_create 내용이 담긴 코드입니다.
for (i = n - 1; i >= 0; i--) { ary[i].x = ary[i].b / ary[i * n + i].a; for (int q = 0; q < tnum; q++) { ary[0].q = q; rc = pthread_create(&threads[q], NULL, parBackSubstitution, ary); assert(rc == 0); } pthread_barrier_wait(&barrier); }
Forums:
스레드가 실행이 안되지는 않을테고...
스레드가 실행이 안되지는 않을테고...
올리신 코드는 변수 i가 전역변수인데..
지역변수여야 할거 같습니다?
구조체 값으로 바꿔보았으나
의견 감사합니다.
parBackSubstitution라는 함수에서 i를 꼭 써야했기에 구조체에 int i를 추가해보았습니다.
메인 함수에서는 계산하는 부분이 아주 약간 바뀌어 이런 코드가 되었고,
함수부분도 그에 맞게 아래와 같이 바꿔보았습니다.
그러나 여전히 threads[0]이 함수를 제대로 수행하지 않습니다...
혹시 pthread_barrier_wait의 위치가 잘못되었을까요?
1. 변수 i를 전역 변수로 만드는 건 상상도 못할
1. 변수 i를 전역 변수로 만드는 건 상상도 못할 짓입니다;
설령 기능적으로는 문제가 없다고 해도, 사람들은 i와 같은 변수는 당연히 지역적으로 사용할 거라고 예상하기 때문이죠.
그런 기대를 저버리는 건 절대 좋다고 할 수가 없습니다.
뭐, 지금은 고치셨으니 그건 넘어가고...
2. 모든 스레드가 동일한 ARY 주소를 공유하는군요.
ary를 동적 배열로 잡으신 걸 보면 스레드마다 하나씩 주고 싶었던 것 같은데, 왜 모든 스레드에 똑같이 주십니까?
보내는 쪽에서는 항상 이렇게 주고
받는 쪽에서는 항상 이렇게 받기 때문에
결국 모든 스레드가 ary[0]만 바라보고 있는 셈이 됩니다.
data race가 발생하는 건 더 말할 것도 없고요. 첫 스레드가 q값을 읽기 전에 메인 스레드에서 q를 바꿔 버리면 어쩌죠?
더 말할 것도 없이 ARY 구조체 셋업은 스레드마다 따로 해 주고, pthread_create에서 ARY 주소를 넘길 때도 각각 다르게 주어야 합니다.
댓글 달기