如何修复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
修复方案及修改后代码
针对问题的具体修复:
解决
PROGRAM END后消费者残留输出问题- 添加全局变量
is_running作为线程退出标志,替代直接调用exit - 生产者在
myCount达到SIZE时,设置is_running为0,广播两个条件变量唤醒所有等待线程,然后退出循环 - 消费者线程循环判断
is_running,同时在等待条件变量时也检查该标志,避免无限等待 - 主线程同时
pthread_join生产者和消费者线程,确保所有线程正常结束后再销毁同步对象
- 添加全局变量
让
PROGRAM START更醒目- 给
PROGRAM START添加前后分隔线和星号标记,比如******** PROGRAM START ********
- 给
调整消费者线程创建提示的位置
- 在主线程创建消费者线程后,先获取互斥锁,输出
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
相关产品推荐
相关产品推荐

