2개의 쓰레드간의 스케쥴링 문제.

alata의 이미지

도와주세요. 계속 고민하고 찾아봐도 마땅한 답이 없어서 올려봅니다.
문제는 이렇습니다.
int array[20]라는 공유하는 배열이 있고요.
메인쓰레드에서 쓰레드2개(create, destroy)를 생성합니다.
create(A)는 array의 빈공간 0인 곳을 찾고 쓰레드를 생성한 후 ID를 빈공간에 씁니다.
destroy(B)는 array의 빈공간이 아닌 곳의 ID를 참조하여 쓰레드를 지운후 0을 다시 씁니다.
이 2개의 쓰레드를 mutex를 통해서 array접근을 보호하였고요.
그런데 이 2개의 A,B쓰레드가 항상 ABABABABABABABABAB 이런식으로 동작이됩니다.
즉, 정확히 A에서 쓰레드를 만들면 다음에 B가 파괴하므로 배열에는 항상 0으로만 가득차게 됩니다.
제가 해결해야할 문제는 A,B 쓰레드의 스케쥴링이 OS에 의해서 랜덤으로 된다고 들었는데 실제로 구현해보니 그렇지 않았습니다.
어떻게 해결해야할까요?? 도와주세요!

void * create(void * array )
{
  int i;
  int * arr = (int *)array;
  pthread_t new_thread;
  while(1)
  {
        pthread_mutex_lock(&mutex);
        pthread_create(&new_thread,0,nullfunc,0);
        i = find_empty_index(arr);
        arr[i]= new_thread;
        array = arr;
        pthread_mutex_unlock(&mutex);
        create_count++;
        printf("arr[.%d] = %d  create count = %d\n",i,arr[i],create_count);
        sleep(1);
  }
}
void * destroy(void  * array)
{
  int i;
  pthread_t new_thread;
  int * arr = (int *)array;
  while(1)
  {
        pthread_mutex_lock(&mutex);
    i = find_full_index(arr);
    if(i!=-1){
        if(pthread_cancel(new_thread)){
                destroy_count++;
                arr[i] = 0;
                printf("destroy_count : %d \n",destroy_count);
        }
        array =arr;
    }
    pthread_mutex_unlock(&mutex);
    sleep(1);
  }
  printf("thread2 behavior.\n");
}
익명 사용자의 이미지

어떤 것을 원하시는지 구체적으로 잘 이해가 안됩니다.

쓰레드 생성과 파괴 루틴 전체에 모두 락이 걸려있고, unlock 뒤에 sleep(1) 이 있으므로
당연히 create -> destroy -> create -> destory 로 동작할 수 밖에 없습니다.

쓰레드 생성 후 다시 생성을 하려면 unlock 후에 바로 lock 을 다시 잡는 경우가 존재해야 하는데
지금과 같은 코드에서 그것은 불가능하므로 당연히 생성과 파괴를 돌아가면서 반복하는 것이 정상입니다.

alata의 이미지

글이 두서가 없어서 죄송합니다.
제가 구현하고자 하는 것은 create(A)와 destroy(B) 두 쓰레드 작동이 동시에 되는 것을 보여주려고합니다.
즉 스케쥴러에 의해 AABAABBABA 와 같은 무작위적으로 순서대로 2개의 쓰레드가 작동해서

AABAABBABA

A = 6개의 쓰레드생성
B = 4개의 쓰레드 파괴
array[0] = 1개의 쓰레드 id
array[1] = 1개의 쓰레드 id
총 2개의 쓰레드가 남아있음.

배열 속에 쓰레드가 남아있게끔 하는 것을 보여주려고합니다.
이것을 구현하는게 가능할지 궁금합니다.

익명 사용자의 이미지

원하시는 것을 하시려면 여러가지 방법이 있겠지만, 일단 sleep(1) 이 있어서는
말씀하신 것처럼 잘 되지 않을 것 같다는 생각입니다.

일단 lock 을 너무 광범위하게 잡고 있으므로, 범위를 줄여보시기 바랍니다.

arr[i] = new_thread;
array = arr

이 두 개의 코드에만 lock 을 걸어주시기 바랍니다.
구체적으로 얘기하자면 쓰기 부분이 있는 곳에만 걸어주시면 됩니다.
destroy 도 마찬가지입니다.

익명 사용자의 이미지

락을 적은 부분만 걸고 SLEEP 함수 지워줘도
프로그램 실행하면 한 순간에 쓰레드를 수만개를 만들면서 지워버리고 결국 그자리네요.
다른 방법이 있을까요??

jick의 이미지

정말로 "랜덤"하게 스케줄링이 되는 것을 보고 싶으시면 sleep(1)을 usleep(random() % 1000000) 같은 걸로 바꿔보시고요,

OS가 스케줄링을 "랜덤"하게 한다는 표현은 어폐가 있는데, 정확히 말하면 "OS는 자기 나름대로의 기준에 의해서 자기 맘대로 스케줄링을 하니까 OS가 무슨 순서로 스케줄링을 할 거라고는 절대 예측할 수 없고 그런 걸 가정한 코드는 제대로 돌아가지 않는다."입니다.

다시 말해서 OS가 "ABABABAB 이렇게 순서대로 스케줄링해야지"라고 마음먹으면 그건 OS 맘입니다. 거기다 대고 "왜 동전 던지기처럼 진짜 랜덤을 안 하는 거야?"라고 항의해 봤자 아무 소용 없습니다. OS는 애당초 동전 던지기를 해주겠다고 약속한 적이 없으니까요.

그리고 해당 코드는 unlock을 한 다음 sleep(1)을 하게 되는데 그러면 쓰레드 하나가 자는 동안 다른 쪽 쓰레드는 1초 동안 스케줄이 될 기회를 잡는 것입니다. 시스템 리소스를 다 먹는 무지막지한 프로그램이 같이 돌고 있다면 모를까, 21세기의 어떤 OS라도 CPU가 놀고 있는 상태에서 1초 동안 스케줄이 될 수 있는 상태로 대기중인 쓰레드를 "넌 랜덤 기회에서 탈락했으니까 그냥 계속 쉬어" 하지는 않습니다.

익명 사용자의 이미지

답변해주신 두분 감사합니다.
실제로 랜덤으로 스케쥴링되는건 확인하지 못했습니다만
많이 배우고 갑니다. 감사합니다.

익명 사용자의 이미지

usleep(random() % 1000000)
로 무작위로 스케쥴링 되는 것 확인했습니다. 감사합니다

익명 사용자의 이미지

말씀하신 것이 누구한테 가르치거나 하는 목적으로 하시는 거라면
usleep(random() % 1000000) 을 이용한 예제는 보여주지 않으시는 것이 좋습니다.

윗 분이 말씀하신 것은, 이런식으로 하면 AABABBAAB.. 등 처럼 랜덤으로 락을 잡는것을
"보여주는" 것이 가능하다는 것이지만, 이건 결과적으로 스케줄링으로 인한 무작위를 보여주는 것은 아닙니다.
출력은 당연히 랜덤하게 되겠지만 그건 랜덤 함수로 슬립을 돌리니 스케줄링에 관계없이 당연한 겁니다.

윗 분 말씀처럼 스케줄링은 랜덤하게 주사위 돌리는 행위가 아닙니다. 따라서 AAAB 와 같은 것을 바라는 것
자체가 일단 잘못되었습니다. 아무리 랜덤하게 된다고 해도 말씀하신 것처럼 만약 AAAB 같은 것이 가능하려면
쓰레드 생성 후 배열 체크하고 값 넣고 printf 하는 등의 모든 작업을 연속 3번 하는 동안 B 의 코드가
한 번도 실행되지 않아야 한다는 것인데, 만약 A 와 B 작업량이 비슷하다면 이는 단순하게 생각해봐도 매우 불합리한 스케줄링입니다.

즉 코드 갯수의 차이를 크게 벌려야 위와 같은 것이 가능하다는 얘기입니다.
물론 이는 단순히 C 레벨에서의 코드를 얘기하는 게 아니라 어셈블리 코드, 시스템 콜 호출 횟수 등
많은 것을 따져야 합니다. 지금은 create 와 destroy 가 그렇게 큰 차이가 없기 때문에 당연히
거의 웬만한 경우는 서로 한 번씩 사이좋게 실행하게 될 겁니다. (당연히 sleep 을 뺐다고 가정할 때)

코드량의 차이를 조금 크게 두면 한 쪽 작업이 다 실행되는 동안 다른 쪽 작업은 2번 이상 실행될
가능성이 증가하므로 이렇게 되면 그나마 usleep(random() % 1000000) 보다는 보여줄만한 예시가 될 수 있습니다.
물론 이 역시 중요한 점은 차이가 너무 크게 되면 AABAABAAB... 식으로 너무 규칙적으로 될 수 있으므로
적절히 조절해서 해야 하는데, 사실 usleep 을 random 으로 하는 거나 별 차이 없게 보일 수 있으나
그래도 이 쪽은 강제로 랜덤하게 sleep 시키는 것이 아니라 스케줄링 타임에 의해서 약간의 차이가 생긴다는 점이 다릅니다.

익명 사용자의 이미지

저는 대학생입니다.
제 질문으로 2분동안 A,B의 쓰레드 호출되는 수를 그래프화 하는것이 과제였습니다.
교수님은 OS에 의해서 일어나는 스케쥴링을 이를
쓰레드가 생성되고 파괴되는 것을 그래프로 보여달라고 한 것이였는데

결과를 보니 역시 ABAB가 반복되는 그래프를 그려서 제출하는게 타당하다고 생각됩니다.

하지만 그래프로 표현하기엔 과제의 의미를 잘 살릴 수 없는 거같기에 ....
말씀해주신 A,B 쓰레드의 작업량의 변화로 수정해본뒤 짧은 소스에서 변화가 나타나지 않는다면.

sleep 함수를 넣은 그래프 하나와
sleep을 넣지않은 수평선의 그래프 2개를 같이 제출하려고합니다.

스케쥴링에 대해 많은 것을 가르쳐주셔서 다시 한 번 감사드립니다.

leadha의 이미지

제가 전에 뮤텍스 관련해서 질문을 하고 대기순으로 순차적 스케쥴링이 보장되지 않는다는 걸 배웠는데, 만약 뮤텍스 스케쥴링에 관해서라면 sleep 을 오히려 안에 넣음으로서 확인할 수 있습니다.

지금은 한 스레드가 락을 잡고 있는 시간이 그렇지 않은 시간보다 훨씬 짧은데, sleep 을 락-언락 사이로 넣어버리면 다른 스레드가 분명히 락을 잡으려고 대기중이었는데 방금 언락을 한 스레드가 다시 락을 잡는 현상이 발생합니다.

그런데 그렇다면 왜 굳이 락 사이에서 숫자만 바꾸지 않고 스레드 생성을 하는지가 궁금한데... 보려는게 뮤텍스 스케쥴링의 임의성이 맞나요?

댓글 달기

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