간단한 pthread 질문

eminency의 이미지

#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에서 실행하니 결과값이 위와 같이 나옵니다.

체스맨의 이미지

컨텍스트 스위치가 언제 일어날지는 커널이 알아서 하는 것이니,
지금과 같은 경우는 main 함수의 두번째 for 루프에서 pthread_join 호출하면서 일어난 것 같군요.
그렇게 되면 두 스레드 모두 main 함수 내에 선언된 i 의 포인터를 넘겨받았으니 그 값이 모두 0으로 찍힐 수 밖에요.

Orion Project : http://orionids.org

eminency의 이미지

음 근데... 저도 그 점을 고려해서 쓰레드 핸들러 내에 다음 부분을 넣은 것인데요.

int id = *((int *)data);

체스맨님 설명대로라면 이 과정도 pthread_join에서 일어나게 되기 때문인 것이 맞나요?

저는 쓰레드 별로 순차적이고 unique한 값을 주려고 시도한 것인데 그럼 다른 방법은 없는지요? ㅡㅡ;

노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5

kicom95의 이미지

for (i=0; i<2; i++)
        {  
                arr[i] = i;
                thr_id = pthread_create(&p_thread[i], NULL, do_loop, (void *)&arr[i]
        } 

이렇게 수정하면 될꺼 같은데요 ^^ 저도 비슷하게 프로그래밍 한적 있습니다.저도 비슷하게 프로그래밍 한적 있습니다.

가자 해외로 ~ .. 돈 벌러.

eminency의 이미지

움.. 이렇게도 짜보긴 했는데... 쓸데없이 공간을 낭비하는 것 같아서 다른 방법이 없나 해서요 ㅡㅡ;;

노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5

kicom95의 이미지

속도는 별 문제 없는 건가요 ?

그럼 pthread_create 를 호출후 sleep(1) 을 주신 다음에 다음 작업을 해보시면....

sleep 호출이 context switch 을 유발 할수도 있기에 ^^ ( 저도 정확히 말씀드리지는 못하지만 ^^ )

어떨까 싶네요...

별도의 배열을 쓰시는게 메모리를 많이 차지 한다고 생각 들지는 않는데요

배열을 char 로 선언하면 단지 쓰레드 당 1byte 를 더 필요로 한건데요... ^^;;

가자 해외로 ~ .. 돈 벌러.

체스맨의 이미지

join 전까지 main 스레드에서 컨텍스트 스위칭이 일어나지 않다가 join 호출 뒤 main 스레드가 블럭되면서 다른 스레드가 실행되도록 스케쥴링 된 것 같습니다. 그래서 말씀하신대로 다음 코드는 join 호출 후에 실행된 것 같습니다.

int id = *((int *)data);

sleep 이 항상 컨텍스트 스위치를 보장할 수 없기 때문에 좋은 방법은 아니고, 별도 메모리 사용이 싫으시면 다음과 같은 방법은 있습니다.

스레드 만들 때,

pthread_create( ..., (char*)0 + i );

스레드에서 값을 받을 때

int id = (char*)data - (char*)0;

하지만, 실제 스레드 프로그래밍시에는 정수값만 넘겨주는 경우가 별로 없을 겁니다. 어차피 스레드마다 메모리를 할당해주거나, TLS 를 이용하겠지요.

Orion Project : http://orionids.org

wfellow의 이미지

Race Condition..

제 기억엔 LDD(Linux Device Driver)의 pdf파일을 보면 고민하시는 내용의 설명이 있을 겁니다.
아마도 5장으로 기억을 하는뎁숑..

ps: LDD 3nd의 라이센스가 희한해서리 받아 보실 수 있을겁니다.
지금 찾아보니 5장의 정확한 제목은 Concurrency and Race Conditions 입니다.

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

haewoo의 이미지

그러한 현상이 발생하는 이유는 복수의 스레드가 아무런 동기화없이
공유된 변수 (여기서는 i)를 사용한다는 것입니다.
이러한 문제를 해결하기 위해서는 반드시 malloc을 호출하여 정수형
변수에 공간을 할당하고 값을 대입한 다음에 사용해야만 합니다.

bugiii의 이미지

void *
do_loop(void *data)
{
int id = *((int *)data); // (int)data 로 수정
int i;

-------------------------

for (i=0; i&lt2; i++)
{
thr_id = pthread_create(&p_thread[i], NULL, do_loop, (void *)&i); // (void*)i 로 수정
}

-------------------------

이렇게 하시면 문제는 바로 해결되겠습니다만, 쓰레드 생성시 넘겨주는 추가적인 인자는 조심해서 다뤄져야합니다. 윗분들 말씀대로 외부변수나 힙에 할당하거나 직접적인 값으로 넘겨주어야 합니다.

지금 문제는 pthread_create 당시 전달되는 값이 i 자체가 아니라 i의 주소이기 때문에, 첫번째 쓰레드 생성 루프가 끝나고 다음 루프에서 i 는 0인 상태에서 join 대기를 하고 있다는 것입니다.

pthread_create 가 약간의 내부적인 (주쓰레드가 아니라 새로운 쓰레드가 생성되는) 딜레이를 갖는다면, 당연히 그렇게 될 확률이 높다는 것을 예상해볼 수 있겠습니다.

eminency의 이미지

음.. 복잡해서 잘 이해 안가는 부분은 있지만 어쨌든 주소값을 넘겨주는 것이 결국 문제가 될 소지가 많은 것이군요. 쓰레드간에 아무래도 저 주소를 공유하게 되니까...

노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.