pthread生产者消费者问题

发布于 2022-09-07 22:40:03 字数 5339 浏览 14 评论 0

需求:
很简单,就是练习使用pthread实现生产者消费者模型

  1. 创建data_queue.c,用于缓存数据
  2. main线程,用于创建生产者和消费者线程

问题

  1. 第一次点击Start按钮,执行start(),程序正常执行
  2. 点击Stop按钮,执行stop(),程序中日志正常打印线程退出信息
  3. 再次点击start按钮,执行start(),生产者和消费者线程只打印一次生产数据和消费数据后,就卡在那里..,不知道是不是死锁??

代码如下:

代码被简化
  • 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("队列中没有数据,等待生产");
        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按钮,执行Java_me_learn_JNIThread_start()函数
  3. 点击Stop按钮,执行Java_me_learn_JNIThread_stop()函数
static pthread_t producer;
static pthread_t consumer;
static int finished_producer = 0;
static int finished_consumer = 0;

void *producer_run(void *userdata) {
    LOGE("生产者线程启动成功...\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 = "生产者线程正常退出";
            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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

北城孤痞 2022-09-14 22:40:03

好吧,是自己反傻了,原来finish标识设置为1之后,再次start的时候没有重新置为0...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文