You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复C语言生产者-消费者程序,使线程在计数器达10时终止

生产者-消费者双线程程序问题修复

问题描述

  • 输出PROGRAM END后,消费者线程仍会继续输出内容,导致PROGRAM END无法成为最后一行日志
  • PROGRAM START在日志中不够醒目,难以快速定位
  • 消费者线程创建的提示CONSUMER THREAD CREATED位置错误,需要出现在第二次myCount递增操作之前

现有代码

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

#define SIZE 10
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t myCond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t myCond2 = PTHREAD_COND_INITIALIZER;
int myCount = 0;

void print_mutex_status(const char* thread, const char* status) {
    printf("%s: myMutex %s\n", thread, status);
}

void print_cond_status(const char* thread, const char* cond) {
    printf("%s: %s\n", thread, cond);
}

void* producer_thread(void* arg) {
    while (1) {
        pthread_mutex_lock(&myMutex);
        print_mutex_status("PRODUCER", "locked");
        while (myCount == SIZE) {
            print_cond_status("PRODUCER", "waiting on myCond1");
            pthread_cond_wait(&myCond1, &myMutex);
        }
        // Produce an item
        printf("myCount: %d -> %d\n", myCount, myCount + 1);
        myCount++;
        pthread_mutex_unlock(&myMutex);
        print_mutex_status("PRODUCER", "unlocked");
        pthread_cond_signal(&myCond2);
        print_cond_status("PRODUCER", "signaling myCond2");
        if (myCount == SIZE) {
            printf("PROGRAM END\n");
            exit(EXIT_SUCCESS); // Corrected line to terminate the program
        }
    }
    return NULL;
}

void* consumer_thread(void* arg) {
    while (1) {
        pthread_mutex_lock(&myMutex);
        print_mutex_status("CONSUMER", "locked");
        while (myCount == 0) {
            print_cond_status("CONSUMER", "waiting on myCond2");
            pthread_cond_wait(&myCond2, &myMutex);
        }
        // Consume an item
        printf("myCount: %d -> %d\n", myCount, myCount - 1);
        myCount--;
        pthread_mutex_unlock(&myMutex);
        print_mutex_status("CONSUMER", "unlocked");
        pthread_cond_signal(&myCond1);
        print_cond_status("CONSUMER", "signaling myCond1");
    }

    return NULL;
}

int main() {
    printf("PROGRAM START\n");
    pthread_t producer, consumer;
    if (pthread_create(&producer, NULL, producer_thread, NULL) != 0) {
        perror("Error creating producer thread");
        exit(EXIT_FAILURE);
    }
    if (pthread_create(&consumer, NULL, consumer_thread, NULL) != 0) {
        perror("Error creating consumer thread");
        exit(EXIT_FAILURE);
    }
    printf("CONSUMER THREAD CREATED\n");
    pthread_join(producer, NULL);
    pthread_mutex_destroy(&myMutex);
    pthread_cond_destroy(&myCond1);
    pthread_cond_destroy(&myCond2);
    return 0;
}

示例输出片段

myCount: 1 -> 0
CONSUMER: myMutex unlocked
CONSUMER: signaling myCond1
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
CONSUMER: myMutex locked
myCount: 1 -> 0
CONSUMER: myMutex unlocked
CONSUMER: signaling myCond1
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
CONSUMER: myMutex locked
myCount: 1 -> 0
CONSUMER: myMutex unlocked
CONSUMER: signaling myCond1
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
CONSUMER: myMutex locked
myCount: 1 -> 0
CONSUMER: myMutex unlocked
CONSUMER: signaling myCond1
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
CONSUMER: myMutex locked
myCount: 1 -> 0
CONSUMER: myMutex unlocked
CONSUMER: signaling myCond1
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
CONSUMER: myMutex locked
myCount: 1 -> 0
CONSUMER: myMutex unlocked
CONSUMER: signaling myCond1
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
CONSUMER: myMutex locked
myCount: 1 -> 0
CONSUMER: myMutex unlocked
PRODUCER: myMutex locked
myCount: 0 -> 1
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 1 -> 2
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 2 -> 3
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 3 -> 4
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 4 -> 5
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 5 -> 6
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 6 -> 7
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 7 -> 8
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 8 -> 9
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PRODUCER: myMutex locked
myCount: 9 -> 10
PRODUCER: myMutex unlocked
PRODUCER: signaling myCond2
PROGRAM END
CONSUMER: signaling myCond1
CONSUMER: signaling myCond1
CONSUMER: myMutex locked

修复方案及修改后代码

针对问题的具体修复:

  1. 解决PROGRAM END后消费者残留输出问题

    • 添加全局变量is_running作为线程退出标志,替代直接调用exit
    • 生产者在myCount达到SIZE时,设置is_running为0,广播两个条件变量唤醒所有等待线程,然后退出循环
    • 消费者线程循环判断is_running,同时在等待条件变量时也检查该标志,避免无限等待
    • 主线程同时pthread_join生产者和消费者线程,确保所有线程正常结束后再销毁同步对象
  2. 让PROGRAM START更醒目

    • 给PROGRAM START添加前后分隔线和星号标记,比如******** PROGRAM START ********
  3. 调整消费者线程创建提示的位置

    • 在主线程创建消费者线程后,先获取互斥锁,输出CONSUMER THREAD CREATED后再释放锁,利用互斥锁的同步性确保提示出现在生产者第二次递增之前

修改后的完整代码

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

#define SIZE 10
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t myCond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t myCond2 = PTHREAD_COND_INITIALIZER;
int myCount = 0;
// 添加退出标志
int is_running = 1;

void print_mutex_status(const char* thread, const char* status) {
    printf("%s: myMutex %s\n", thread, status);
}

void print_cond_status(const char* thread, const char* cond) {
    printf("%s: %s\n", thread, cond);
}

void* producer_thread(void* arg) {
    while (is_running) {
        pthread_mutex_lock(&myMutex);
        print_mutex_status("PRODUCER", "locked");
        // 等待时同时检查退出标志
        while (myCount == SIZE && is_running) {
            print_cond_status("PRODUCER", "waiting on myCond1");
            pthread_cond_wait(&myCond1, &myMutex);
        }
        // 如果已经退出,解锁后结束
        if (!is_running) {
            pthread_mutex_unlock(&myMutex);
            break;
        }
        // Produce an item
        printf("myCount: %d -> %d\n", myCount, myCount + 1);
        myCount++;
        pthread_mutex_unlock(&myMutex);
        print_mutex_status("PRODUCER", "unlocked");
        pthread_cond_signal(&myCond2);
        print_cond_status("PRODUCER", "signaling myCond2");
        
        if (myCount == SIZE) {
            // 设置退出标志
            pthread_mutex_lock(&myMutex);
            is_running = 0;
            pthread_mutex_unlock(&myMutex);
            // 广播所有条件变量,唤醒等待的线程
            pthread_cond_broadcast(&myCond1);
            pthread_cond_broadcast(&myCond2);
            printf("******** PROGRAM END ********\n");
            break;
        }
    }
    return NULL;
}

void* consumer_thread(void* arg) {
    while (is_running) {
        pthread_mutex_lock(&myMutex);
        print_mutex_status("CONSUMER", "locked");
        // 等待时同时检查退出标志
        while (myCount == 0 && is_running) {
            print_cond_status("CONSUMER", "waiting on myCond2");
            pthread_cond_wait(&myCond2, &myMutex);
        }
        // 如果已经退出,解锁后结束
        if (!is_running) {
            pthread_mutex_unlock(&myMutex);
            break;
        }
        // Consume an item
        printf("myCount: %d -> %d\n", myCount, myCount - 1);
        myCount--;
        pthread_mutex_unlock(&myMutex);
        print_mutex_status("CONSUMER", "unlocked");
        pthread_cond_signal(&myCond1);
        print_cond_status("CONSUMER", "signaling myCond1");
    }
    return NULL;
}

int main() {
    // 让启动信息更醒目
    printf("******** PROGRAM START ********\n");
    pthread_t producer, consumer;
    if (pthread_create(&producer, NULL, producer_thread, NULL) != 0) {
        perror("Error creating producer thread");
        exit(EXIT_FAILURE);
    }
    if (pthread_create(&consumer, NULL, consumer_thread, NULL) != 0) {
        perror("Error creating consumer thread");
        exit(EXIT_FAILURE);
    }
    // 用互斥锁保证创建提示的输出时机
    pthread_mutex_lock(&myMutex);
    printf("CONSUMER THREAD CREATED\n");
    pthread_mutex_unlock(&myMutex);
    
    // 等待两个线程都结束
    pthread_join(producer, NULL);
    pthread_join(consumer, NULL);
    
    pthread_mutex_destroy(&myMutex);
    pthread_cond_destroy(&myCond1);
    pthread_cond_destroy(&myCond2);
    return 0;
}

内容的提问来源于stack exchange,提问作者Anthony Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:39:50