鍍金池/ 問答/C  C++  Linux/ pthread生產(chǎn)者消費者問題

pthread生產(chǎn)者消費者問題

需求:
很簡單,就是練習(xí)使用pthread實現(xiàn)生產(chǎn)者消費者模型

  1. 創(chuàng)建data_queue.c,用于緩存數(shù)據(jù)
  2. main線程,用于創(chuàng)建生產(chǎn)者和消費者線程

問題

  1. 第一次點擊Start按鈕,執(zhí)行start(),程序正常執(zhí)行
  2. 點擊Stop按鈕,執(zhí)行stop(),程序中日志正常打印線程退出信息
  3. 再次點擊start按鈕,執(zhí)行start(),生產(chǎn)者和消費者線程只打印一次生產(chǎn)數(shù)據(jù)和消費數(shù)據(jù)后,就卡在那里..,不知道是不是死鎖??

代碼如下:

代碼被簡化
  • data_queue.c

#define MAX_QUEUE_SIZE 10

int student_queue_init(StudentQueue *queue) {
    memset(queue, 0, sizeof(StudentQueue));
    pthread_mutex_init(&queue->mutex, NULL);
    pthread_cond_init(&queue->empty_queue, NULL);
    pthread_cond_init(&queue->full_queue, NULL);
    return 0;
}

int student_queue_put(StudentQueue *queue, Student student) {
    pthread_mutex_lock(&queue->mutex);
    while (queue->nb_students == (MAX_QUEUE_SIZE - 1)) {
        LOGE("隊列已滿,等待消費");
        pthread_cond_wait(&queue->full_queue, &queue->mutex);
    }

    StudentNode *node = (StudentNode *) malloc(sizeof(StudentNode));
    node->student = student;
    node->next = NULL;
    if (!queue->rear) {
        queue->front = node;
    } else {
        queue->rear->next = node;
    }
    queue->rear = node;
    queue->nb_students++;
    pthread_cond_signal(&queue->empty_queue);
    pthread_mutex_unlock(&queue->mutex);
    return 0;
}

int student_queue_get(StudentQueue *queue, Student *student) {
    pthread_mutex_lock(&queue->mutex);
    while (queue->nb_students <= 0) {
        LOGE("隊列中沒有數(shù)據(jù),等待生產(chǎn)");
        pthread_cond_wait(&queue->empty_queue, &queue->mutex);
    }
    StudentNode *node = queue->front;
    *student = node->student;
    queue->front = node->next;
    if (!queue->front) {
        queue->rear = NULL;
    }
    queue->nb_students--;
    pthread_cond_signal(&queue->full_queue);
    pthread_mutex_unlock(&queue->mutex);
    return 0;
}

int student_queue_destroy(StudentQueue *queue) {
    pthread_mutex_lock(&queue->mutex);
    StudentNode *temp;
    for (temp = queue->front; temp; temp = temp->next) {
        free(temp);
    }
    queue->front = NULL;
    queue->rear = NULL;
    pthread_mutex_unlock(&queue->mutex);
    pthread_mutex_destroy(&queue->mutex);
    pthread_cond_destroy(&queue->empty_queue);
    pthread_cond_destroy(&queue->full_queue);
    free(queue);
    return 0;
}
  • main.c

解釋一下main.c

  1. Android中的JNI小栗子
  2. 點擊Start按鈕,執(zhí)行Java_me_learn_JNIThread_start()函數(shù)
  3. 點擊Stop按鈕,執(zhí)行Java_me_learn_JNIThread_stop()函數(shù)
static pthread_t producer;
static pthread_t consumer;
static int finished_producer = 0;
static int finished_consumer = 0;

void *producer_run(void *userdata) {
    LOGE("生產(chǎn)者線程啟動成功...\n");
    StudentQueue *queue = (StudentQueue *) userdata;
    int age = 0;
    while (1) {
        Student student;
        student.age = age++;
        sprintf(student.name, "name ... %d", student.age);
        LOGI("Producer: {age: %d, name: %s}", student.age, student.name);
        student_queue_put(queue, student);
        sleep(1);
        if (finished_producer) {
            Status *status = (Status *) malloc(sizeof(Status));
            status->code = 1001;
            status->msg = "生產(chǎn)者線程正常退出";
            status->opaque = queue;
            pthread_exit((void *) status);
        }
    }
}

void *consumer_run(void *userdata) {
    LOGE("消費者線程啟動成功...\n");
    StudentQueue *queue = (StudentQueue *) userdata;
    while (1) {
        Student student;
        student_queue_get(queue, &student);
        sleep(1);
        LOGE("Consumer: {age: %d, name: %s}", student.age, student.name);
        if (finished_consumer) {
            Status *status = (Status *) malloc(sizeof(Status));
            status->code = 1001;
            status->msg = "消費者線程正常退出";
            status->opaque = queue;
            pthread_exit((void *) status);
        }
    }
}

extern "C"
JNIEXPORT void JNICALL
Java_me_learn_JNIThread_start(JNIEnv *env, jobject instance) {
    StudentQueue *queue = (StudentQueue *) malloc(sizeof(StudentQueue));
    student_queue_init(queue);

    pthread_create(&producer, NULL, producer_run, (void *) queue);
    pthread_setname_np(producer, "producer");
    pthread_create(&consumer, NULL, consumer_run, (void *) queue);
    pthread_setname_np(consumer, "consumer");
}

extern "C"
JNIEXPORT void JNICALL
Java_me_learn_JNIThread_stop(JNIEnv *env, jobject instance) {
    finished_producer = 1;
    finished_consumer = 1;

    void *status_producer;
    pthread_join(producer, &status_producer);
    Status *ret_producer = (Status *) status_producer;
    LOGE("[%d]: %s", ret_producer->code, ret_producer->msg);
    free(ret_producer);

    void *status_consumer;
    pthread_join(consumer, &status_consumer);
    Status *ret_consumer = (Status *) status_consumer;
    LOGE("[%d]: %s", ret_consumer->code, ret_consumer->msg);
    free(ret_consumer);

    student_queue_destroy((StudentQueue *) ret_consumer->opaque);

    producer = 0;
    consumer = 0;
}
回答
編輯回答
祈歡

好吧,是自己反傻了,原來finish標識設(shè)置為1之后,再次start的時候沒有重新置為0...

2018年8月19日 15:46