cond & mutex 를 이용한 쓰레드 동기화 문제

air74의 이미지

쓰레드를 이용하여 producer/consumer 구조로 프로그램을 개발 하려고 합니다.

예상 하는 동작 순서는
producer->consumer->producer->consumer ......순으로 반복 되어야 합니다.

하지만 실제적으로는
producer->consumer 가 한번만 수행이 되고는 다시 producer 가 깨어나질 않습니다.

혹시 sleep 을 안 주어서 그런것인지?? pthread_cond_signal을 사용하는데 sleep 이 필요 한것인지 ..

더욱더 정확하고 성능에 지장이 없는 동기화 방법에 대한 조언 좀 해주세요.

다음은 간략한 소스코드 입니다.

typedef struct shared_buffer {
  pthread_mutex_t lock;      
  pthread_cond_t cond;     
} shared_buffer_t;

void sb_init(shared_buffer_t *sb) {
  pthread_mutex_init(&sb->lock, NULL);    /* lock ... */
  pthread_cond_init(&sb->cond, NULL);     /* cond ... */
}

void sb_destroy(shared_buffer_t *sb) {
  pthread_mutex_destroy(&sb->lock);    /* lock .. */
  pthread_cond_destroy(&sb->cond);     /* cond .. */
}

void producer(shared_buffer_t *sb) {

  while (TRUE) {

    pthread_mutex_lock (&sb->lock);                   
    pthread_cond_wait(&sb->cond, &sb->lock);
    printf("producer\n");
    pthread_cond_signal (&sb->cond);                  
    pthread_mutex_unlock(&sb->lock);
  }
}

main() {
  pthread_t th1;  /* ... thread */
  shared_buffer_t sb;  /* .. ... */

  sb_init(&sb);
  pthread_create(&th1, NULL, (void *) producer, &sb); /* producer .. */
  usleep(1);
  while (TRUE) {       /* consumer 역할을 수행 */
    pthread_mutex_lock(&sb.lock);
    pthread_cond_signal(&sb.cond);                     
    pthread_cond_wait(&sb.cond, &sb.lock);
    printf("consumer\n");
    pthread_mutex_unlock (&sb.lock);
    //usleep(0);   --->  이것이 필요 한지? 가급적이면 사용안했으면합니다.
  }
  pthread_join(th1, NULL);
  sb_destroy(&sb);
}
mach의 이미지

#include <pthread.h>
#define TRUE 1
#define FALSE 0
typedef struct shared_buffer {
  pthread_mutex_t lock;
  pthread_cond_t condF, condE;
} shared_buffer_t;

void sb_init(void *vp) {
  shared_buffer_t *sb;

  sb = (shared_buffer_t *)vp;
  pthread_mutex_init(&sb->lock, NULL);    /* lock ... */
  pthread_cond_init(&sb->condF, NULL);     /* cond ... */
  pthread_cond_init(&sb->condE, NULL);     /* cond ... */
}

void sb_destroy(void *vp) {
  shared_buffer_t *sb;

  sb = (shared_buffer_t *)vp;
  pthread_mutex_destroy(&sb->lock);    /* lock .. */
  pthread_cond_destroy(&sb->condF);     /* cond .. */
  pthread_cond_destroy(&sb->condE);     /* cond .. */
}

volatile int xxx;
void producer(void *vp) {
  shared_buffer_t *sb;

  sb = (shared_buffer_t *)vp;

  while (TRUE) {
    pthread_mutex_lock (&sb->lock);
    while ( xxx != 0 ) {
       //printf("wait for CONSUME %d\n", xxx);
       pthread_cond_wait(&sb->condF, &sb->lock);
    }
    printf("PRODUCE\n");
    xxx++;
    pthread_mutex_unlock(&sb->lock);
    pthread_cond_signal (&sb->condE);
  }
}
void consumer(void *vp) {
  shared_buffer_t *sb;

  sb = (shared_buffer_t *)vp;

  while (TRUE) {
    pthread_mutex_lock(&sb->lock);
    while ( xxx == 0 ) {
       //printf("wait for produce %d\n", xxx);

       pthread_cond_wait(&sb->condE, &sb->lock);
    }
    printf("CONSUME\n");
    xxx--;
    pthread_mutex_unlock (&sb->lock);
    pthread_cond_signal(&sb->condF);
  }
}

main() {
  pthread_t th1, th2,th3;  /* ... thread */
  shared_buffer_t sb;  /* .. ... */

  xxx = 0;
  sb_init(&sb);
  pthread_create(&th1, NULL, (void *) producer, &sb); /* producer .. */
 // pthread_create(&th3, NULL, (void *) producer, &sb); /* producer .. */
  pthread_create(&th2, NULL, (void *) consumer, &sb); /* consumer .. */
  pthread_join(th1, NULL);
  pthread_join(th2, NULL);
 // pthread_join(th3, NULL);
  sb_destroy(&sb);
}

multiple producer들인 경우와 consumer가 다수개인 경우도 테스트해보세요.

천천히 읽어보시기 바랍니다.

sleep() 시리즈(usleep, sleep,...)를 넣어서 동기화하는 것은 아주 위험한 방법입니다. 아니고, ... 동기화에, 사용할 수 없는 것입니다.

또한 pthread_cond_wait() man 페이지를 잘 읽어보세요.
pthread_cond_wait()가 블록상태(block)에서 탈출하는 경우는 pthread_cond_signal()에 의해서만은 아니며, 이를 고려한 코딩을 해야합니다.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

air74의 이미지

훌륭한 답변 감사 드립니다.
좋은 하루 되세요. ^^

어설푼 이..

alone의 이미지

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

typedef struct shared_buffer
{
    pthread_mutex_t lock;
    pthread_cond_t cond;
} shared_buffer_t;


void sb_init(shared_buffer_t *);
void sb_destroy(shared_buffer_t *);
void * producer(void *);

void sb_init(shared_buffer_t *sb)
{
    pthread_mutex_init(&sb->lock, NULL);
    pthread_cond_init(&sb->cond, NULL);
}

void sb_destroy(shared_buffer_t *sb)
{
    pthread_mutex_destroy(&sb->lock);
    pthread_cond_destroy(&sb->cond);
}

int iFlag1 = 1;
int iFlag2 = 0;

void * producer(void * info)
{
    shared_buffer_t * sb = (shared_buffer_t *)info;

    int i = 0;
    while(i < 100000)
    {
        pthread_mutex_lock(&sb->lock);

        while(iFlag1 == 0)
            pthread_cond_wait(&sb->cond, &sb->lock);

        printf("[%d]producer\n", i++);

        iFlag1 = 0;
        iFlag2 = 1;

        pthread_cond_signal(&sb->cond);

        pthread_mutex_unlock(&sb->lock);
    }
}

int main(int argc, char ** argv)
{
    pthread_t th1;
    shared_buffer_t sb;

    sb_init(&sb);
    pthread_create(&th1, NULL, &producer, (void *)&sb);

    int i = 0;
    while(i < 100000)
    {
        pthread_mutex_lock(&sb.lock);

        while(iFlag2 == 0)
            pthread_cond_wait(&sb.cond, &sb.lock);

        printf("[%d]consumer\n", i++);

        iFlag1 = 1;
        iFlag2 = 0;

        pthread_cond_signal(&sb.cond);

        pthread_mutex_unlock(&sb.lock);
    }
    pthread_join(th1, NULL);
    sb_destroy(&sb);

    return 0;
}

내일은 내일일뿐.....

댓글 달기

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