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를 추가해보았습니다.
메인 함수에서는 계산하는 부분이 아주 약간 바뀌어 이런 코드가 되었고,
for (int i = n - 1; i >= 0; i--) { ary[0].i = 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); }함수부분도 그에 맞게 아래와 같이 바꿔보았습니다.
void* parBackSubstitution(void* ary) { ARR* ar = (ARR*)ary; int q = ar[0].q; int i = ar[0].i; 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); }그러나 여전히 threads[0]이 함수를 제대로 수행하지 않습니다...
혹시 pthread_barrier_wait의 위치가 잘못되었을까요?
1. 변수 i를 전역 변수로 만드는 건 상상도 못할
1. 변수 i를 전역 변수로 만드는 건 상상도 못할 짓입니다;
설령 기능적으로는 문제가 없다고 해도, 사람들은 i와 같은 변수는 당연히 지역적으로 사용할 거라고 예상하기 때문이죠.
그런 기대를 저버리는 건 절대 좋다고 할 수가 없습니다.
뭐, 지금은 고치셨으니 그건 넘어가고...
2. 모든 스레드가 동일한 ARY 주소를 공유하는군요.
ary를 동적 배열로 잡으신 걸 보면 스레드마다 하나씩 주고 싶었던 것 같은데, 왜 모든 스레드에 똑같이 주십니까?
보내는 쪽에서는 항상 이렇게 주고
받는 쪽에서는 항상 이렇게 받기 때문에
결국 모든 스레드가 ary[0]만 바라보고 있는 셈이 됩니다.
data race가 발생하는 건 더 말할 것도 없고요. 첫 스레드가 q값을 읽기 전에 메인 스레드에서 q를 바꿔 버리면 어쩌죠?
더 말할 것도 없이 ARY 구조체 셋업은 스레드마다 따로 해 주고, pthread_create에서 ARY 주소를 넘길 때도 각각 다르게 주어야 합니다.
댓글 달기