쓰레드 프로그래밍 질문이에요.

joungis의 이미지

int arg;

arg=1
pthread_create(&tid1, NULL, &func1, &arg);
pthread_detach(tid1);

arg=2
pthread_create(&tid2, NULL, &func2, &arg);
pthread_detach(tid2);

arg=3
pthread_create(&tid3, NULL, &func3, &arg);
pthread_detach(tid3);

arg=4
pthread_create(&tid4, NULL, &func4, &arg);
pthread_detach(tid4);

프로그램은 대충 이렇습니다.
그런데 func1, func2, func3, func4 함수는 각각 인자를 1,2,3,4 로 받아와야 하는데
printf로 찍어 보면 전부 4가 찍히네요.
이거 뭔가 이상한가요? 쓰레드를 저런식으로 운용하는게 잘못된건가요?

그리고 한가지만 더요.
솔라리스 8인데요, -mt 옵션 주고 아래 소스를 컴파일을 했습니다.
#include
#include
#include
void main()
{
sleep(120);
}

실행해서 top 으로 보면 LWP 항목이 6이라고 되어있네요. 쓰레드는 생성하지도 않았는데요.
이건 또 어떻게 이해를 해야하나요? 제가 쓰레드에 이해가 좀 부족한거 같은데 괜찮은 문서좀
추천해주세요. 감사합니다.

grassman의 이미지

변수 arg의 주소를 thread의 argument로 전달했기 때문에 모든 thread가 같은 변수를 보고 있는 겁니다. arg의 최종 값은 4이므로 계속 4가 나온 것입니다.

솔라리스에 대해서는 아는 바가 없으므로 넘어갑니다.

codepage의 이미지

님의 코드의 경우 정답은 '어떤 값이 찍힐 지 알 수 없다.'입니다.
쓰레드 내의 코드들은 스레드를 호출한 코드와 독립적으로 동작하기 때문에
필수적으로 동기화 문제를 생각해야 합니다.
arg=2가 실행되기 전에 실행한 쓰레드의 printf가 먼저 작동한다면 결과값이 1이 찍힐 것이고
그렇지 않다면 2가 찍히겠죠.

또한 arg를 local variable로 선언하고 사용했다면 일반적으로 Stack영역에 변수가 존재할텐데
소멸되어 버린 이후 다른 쓰래드에서 참조된다면 segmentation fault 혹은 page fault가 떨어져서
프로그램 다운될 것입니다(OS가 종료시킴.)

또한 Top으로 볼 때 LWP문제는
'어플리케이션이 동작할 때 기본적으로 여러개의 쓰래드가 동작할 수 있고 이것은 플랫폼마다 차이가 난다.'
라고 볼 수 있습니다.

sharefeel의 이미지

핵심은..
thread를 생성하기 전에 arg에 새로운 메모리를 할당한 후 그 주소를 파라미터로 넘깁니다.
이렇게 하면 각 스레드가 모두 다른 주소의 arg를 참조하므로 같은 값이 출력되진 않겠죠.
할당된 메모리의 해제는 thread 자체에게 있습니다.

unp에서 대충 긁어온 소스입니다.

int main(...)
{
	int *arg;
 
	arg = (int *) malloc(sizeof(int));
	*arg = 1
	pthread_create(&tid1, NULL, &func1, arg);
 
	arg = (int *) malloc(sizeof(int));
	*arg=2
	pthread_create(&tid1, NULL, &func1, arg);
 
	:
}
 
void * func1(void *arg)
{
	int passed_arg;
 
	passed_arg	= *((int *) arg);
	free(arg);
 
	pthread_detach(pthread_self());
	:
	:
}

===============
Vas Rel Por

===============
Vas Rel Por

pizza1977의 이미지

main에서 할당한 arg 변수를
각각의 쓰레드에서 해제하는게 좀 걸리네요.
free 앞쪽에서 특정 쓰레드가 sleep 되는 경우가 발생하면
더 복잡한 일이 발생할 것 같은데요.

포탈이는 불사신

-------------
포탈이는 불사신

sharefeel의 이미지

제목 그대로..
===============
Vas Rel Por

===============
Vas Rel Por

pizza1977의 이미지

리소스 생성, 해제에 대한 기준을
"자기가 생성한 리소스는 자기가 해제한다."라고
가정했기 때문에 free에 대해 언급했던 겁니다.;;;
A에서 생성한 리소스를 B에서 사용한다는 건 A에서
더이상 리소스를 사용하지 않는다는 것이 전제되어야 합니다.
위는 그냥 예를 드신 것이니까 별 문제 없겠습니다만 걍 노파심에;;

sleep 문제는 위 예는 단순히 대입 절차만이 있음으로 별 문제 없어 보입니다만
sleep과 관련된 특정 로직이 즉,

void *run(void *arg)
{
int val = getValue(arg);
....
free(arg);
}

이런 경우 getValue의 sleep 여부 또는 ....부분의
스위칭에 의해 main에서 생성한 arg 리소스가
또다른 쓰레드에서 사용될 수 있다는 얘기였습니다.

포탈이는 불사신

-------------
포탈이는 불사신

sharefeel의 이미지

int main(...)
{
	int *arg;
 
	arg = (int *) malloc(sizeof(int));
	*arg = 1
	pthread_create(&tid1, NULL, &func1, arg);

이 곳에서 *arg = 88; 와 같은 작업을 할 경우 문제가 있다는 말씀이신지요?
	arg = (int *) malloc(sizeof(int));
	*arg=2
	pthread_create(&tid1, NULL, &func1, arg);
 
	:
}

당연히 pthread_create(...)malloc(...) 사이에서 arg에 대해 작업할 경우 문제가 됩니다.
하지만 arg에 할당된 메모리는 다른 데이터가 저장된 주소를 가르키려는 목적이 아닙니다.
arg에 메모리를 할당하는 이유는 단지 파라미터를 안전하게 넘기기 위함입니다.
멀티스레드 환경에서 call-by-reference로 call-by-value를 구현하기 위하기 위해서.. 라고 하면 맞을 듯 합니다.

만약 데이터가 저장된 주소 스레드에 넘기고자 한다면 코드는 다음과 같이 될 것입니다.

int main(...)
    int *data;
    int **arg;
 
    data    = (int *) malloc(sizeof(int));
    *data   = 1;
    arg = (int **) malloc(sizeof(int *));
    *arg    = data;
    pthread_create(&tid1, NULL, &func1, arg);
 
    data    = (int *) malloc(sizeof(int));
    *data   = 2;
    arg = (int **) malloc(sizeof(int *));
    *arg    = data;
    pthread_create(&tid1, NULL, &func1, arg);
}
 
void *func1(void *arg)
{
    int *passed_arg;
    int passed_data;
 
    passed_arg = *((int *) arg);
    free(arg);
 
    passed_data = *(passed_arg);
    printf("%d\n", passed_data);
 
    pthread_detach(pthread_self());
}

중요한 것은 arg가 리소스를 직접 가르켜서는 안된다는 겁니다.
arg 에는 리소스의 주소가 아니라 리소스를 가르키는 변수의 주소가 들어 있어야 합니다.
이렇게 하면 parameter passing 과정에서 다른 스레드에 의해 리소스가 수정되지 않습니다.

===============
Vas Rel Por

===============
Vas Rel Por

pizza1977의 이미지

최초에 올리신 예제도 별 문제는 없습니다.
단지 쓰레 글쓴이 분이 sharefeel님의 예제를 보고 단지 지역 변수가 아닌
malloc을 통한 힙 할당을 통해 자원의 생명줄을 연장하는 것으로 문제가
해결될 수 있다고 생각할 수 있어 올린 글이었습니다.

날씨가 미쳤나 보네요^^;;

포탈이는 불사신

-------------
포탈이는 불사신

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.