간단한 pthread 질문
글쓴이: eminency / 작성시간: 금, 2006/06/30 - 2:16오후
#include <unistd.h> #include <pthread.h> int ncount; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void * do_loop(void *data) { int id = *((int *)data); int i; int mydata; for (i=0; i<10; i++) { pthread_mutex_lock(&mutex); printf("thread %d : %d\n", id, ncount); mydata = ncount; mydata++; usleep(1000); ncount = mydata; pthread_mutex_unlock(&mutex); usleep(10); } return NULL; } int main() { int thr_id; pthread_t p_thread[3]; int status; int i; ncount = 0; for (i=0; i<2; i++) { thr_id = pthread_create(&p_thread[i], NULL, do_loop, (void *)&i); } for (i=0; i<2; i++) pthread_join(p_thread[i], (void *) &status); status = pthread_mutex_destroy(&mutex); printf("end..\n"); return 0; }
위 코드를 실행시켰을 때 (void *)&i로 쓰레드에 넘겨준 인자값이 모두 0으로 디스플레이됩니다.
이해가 안되네요..;
thread 0 : 0
thread 0 : 1
thread 0 : 2
thread 0 : 3
thread 0 : 4
thread 0 : 5
thread 0 : 6
thread 0 : 7
thread 0 : 8
thread 0 : 9
thread 0 : 10
thread 0 : 11
thread 0 : 12
thread 0 : 13
thread 0 : 14
thread 0 : 15
thread 0 : 16
thread 0 : 17
thread 0 : 18
thread 0 : 19
end..
thread 0과 thread 1이 섞여서 찍혀야 정상적인 것이 아닌지요?
레드햇 커널 2.4에서 실행해봤을 때는 제대로 나왔는데 젠투 커널 2.6에서 실행하니 결과값이 위와 같이 나옵니다.
Forums:
컨텍스트 스위치가
컨텍스트 스위치가 언제 일어날지는 커널이 알아서 하는 것이니,
지금과 같은 경우는 main 함수의 두번째 for 루프에서 pthread_join 호출하면서 일어난 것 같군요.
그렇게 되면 두 스레드 모두 main 함수 내에 선언된 i 의 포인터를 넘겨받았으니 그 값이 모두 0으로 찍힐 수 밖에요.
Orion Project : http://orionids.org
음 근데... 저도 그
음 근데... 저도 그 점을 고려해서 쓰레드 핸들러 내에 다음 부분을 넣은 것인데요.
int id = *((int *)data);
체스맨님 설명대로라면 이 과정도 pthread_join에서 일어나게 되기 때문인 것이 맞나요?
저는 쓰레드 별로 순차적이고 unique한 값을 주려고 시도한 것인데 그럼 다른 방법은 없는지요? ㅡㅡ;
노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5
이렇게 한번 써보면 어떨까요 ?
이렇게 수정하면 될꺼 같은데요 ^^ 저도 비슷하게 프로그래밍 한적 있습니다.저도 비슷하게 프로그래밍 한적 있습니다.
가자 해외로 ~ .. 돈 벌러.
움.. 이렇게도 짜보긴
움.. 이렇게도 짜보긴 했는데... 쓸데없이 공간을 낭비하는 것 같아서 다른 방법이 없나 해서요 ㅡㅡ;;
노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5
음...
속도는 별 문제 없는 건가요 ?
그럼 pthread_create 를 호출후 sleep(1) 을 주신 다음에 다음 작업을 해보시면....
sleep 호출이 context switch 을 유발 할수도 있기에 ^^ ( 저도 정확히 말씀드리지는 못하지만 ^^ )
어떨까 싶네요...
별도의 배열을 쓰시는게 메모리를 많이 차지 한다고 생각 들지는 않는데요
배열을 char 로 선언하면 단지 쓰레드 당 1byte 를 더 필요로 한건데요... ^^;;
가자 해외로 ~ .. 돈 벌러.
join 전까지 main
join 전까지 main 스레드에서 컨텍스트 스위칭이 일어나지 않다가 join 호출 뒤 main 스레드가 블럭되면서 다른 스레드가 실행되도록 스케쥴링 된 것 같습니다. 그래서 말씀하신대로 다음 코드는 join 호출 후에 실행된 것 같습니다.
sleep 이 항상 컨텍스트 스위치를 보장할 수 없기 때문에 좋은 방법은 아니고, 별도 메모리 사용이 싫으시면 다음과 같은 방법은 있습니다.
스레드 만들 때,
스레드에서 값을 받을 때
하지만, 실제 스레드 프로그래밍시에는 정수값만 넘겨주는 경우가 별로 없을 겁니다. 어차피 스레드마다 메모리를 할당해주거나, TLS 를 이용하겠지요.
Orion Project : http://orionids.org
Race Condition..
Race Condition..
제 기억엔 LDD(Linux Device Driver)의 pdf파일을 보면 고민하시는 내용의 설명이 있을 겁니다.
아마도 5장으로 기억을 하는뎁숑..
ps: LDD 3nd의 라이센스가 희한해서리 받아 보실 수 있을겁니다.
지금 찾아보니 5장의 정확한 제목은 Concurrency and Race Conditions 입니다.
-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----
-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----
메모리를 따로 할당해야 합니다.
그러한 현상이 발생하는 이유는 복수의 스레드가 아무런 동기화없이
공유된 변수 (여기서는 i)를 사용한다는 것입니다.
이러한 문제를 해결하기 위해서는 반드시 malloc을 호출하여 정수형
변수에 공간을 할당하고 값을 대입한 다음에 사용해야만 합니다.
쓰레드 생성시 전달하는 인자의 문제
void *
do_loop(void *data)
{
int id = *((int *)data); // (int)data 로 수정
int i;
-------------------------
for (i=0; i<2; i++)
{
thr_id = pthread_create(&p_thread[i], NULL, do_loop, (void *)&i); // (void*)i 로 수정
}
-------------------------
이렇게 하시면 문제는 바로 해결되겠습니다만, 쓰레드 생성시 넘겨주는 추가적인 인자는 조심해서 다뤄져야합니다. 윗분들 말씀대로 외부변수나 힙에 할당하거나 직접적인 값으로 넘겨주어야 합니다.
지금 문제는 pthread_create 당시 전달되는 값이 i 자체가 아니라 i의 주소이기 때문에, 첫번째 쓰레드 생성 루프가 끝나고 다음 루프에서 i 는 0인 상태에서 join 대기를 하고 있다는 것입니다.
pthread_create 가 약간의 내부적인 (주쓰레드가 아니라 새로운 쓰레드가 생성되는) 딜레이를 갖는다면, 당연히 그렇게 될 확률이 높다는 것을 예상해볼 수 있겠습니다.
음.. 복잡해서 잘
음.. 복잡해서 잘 이해 안가는 부분은 있지만 어쨌든 주소값을 넘겨주는 것이 결국 문제가 될 소지가 많은 것이군요. 쓰레드간에 아무래도 저 주소를 공유하게 되니까...
노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5
댓글 달기