生产者消费者问题实现遇阻:疑似陷入无限循环求排查
生产者消费者问题排查与修复
问题概述
尝试实现生产者消费者模型,程序疑似陷入无限循环,无法得到预期输出。需求是每生产一个元素,消费者就执行一次排序输出操作。
原始代码
#define MAX_NUM 30 // borne sup des valeurs du tableau #include <pthread.h> #define MAX_SIZE 100 // taille maximale du tableau #include <stdio.h> #include <stdlib.h> int tab [MAX_SIZE]; int size_tab ; int Veut_entrer[2]; int Tour=0; //1 equals to true and 0 equals to false typedef unsigned int uint; //on declare le type variable globale void* lock(int index) { Veut_entrer[Tour]=1; Tour=1-index; while(Veut_entrer[1-index]==1 && Tour==1-index) { //on attend } } void unlock(Tour) { Veut_entrer[Tour]=0; } void * produce ( int index ) { uint count = 0; while ( count < 5) { debut section critique lock(Tour); //printf("Oui ou non %d et %d" ,Veut_entrer[index],Tour); tab [size_tab ++] = rand() % MAX_NUM ; printf ("produce : %d\n", tab[size_tab-1]); fin section critique unlock(Tour); //printf("hein"); count ++; //printf("ici"); return (NULL);} } int compare ( const void* a , const void* b ) { int const* pa = a ; int const* pb = b ; return (*pb - *pa ); } void* consume ( int index ) { uint count = 0; printf("stuck"); //printf("Oui ou non %d " ,Veut_entrer[0]); while ( count != 5) { if ( count < size_tab ) { printf("stuck"); debut section critique lock(index); //printf("Oui ou non %d et %d" ,Veut_entrer[index],Tour); qsort(tab ,MAX_SIZE / sizeof(int) ,sizeof(int) ,compare);//algortiheme qui permet de trier le tableau tant que la taille du tableau est inférieur a 5=count printf("consume : sort [%d elements] =>" ,size_tab); for(uint i = 0; i < size_tab ; i ++) printf ( " %d" , tab[i]); printf ( "\n" ); count = size_tab ; fin section critique unlock(index); } } return(NULL); } int init() { Veut_entrer[0]=0; Veut_entrer[1]=0; } int main (){ int index_prod=0; int index_cons=1; pthread_t thread1 ; pthread_t thread2 ; char* m1 = " mon parametre " ; char* m2="truc"; //printf("ici erreur"); init(); //printf("Oui ou non %d " ,Veut_entrer[0]); //produce(index); //consume(index); //printf("erreu"); pthread_create (&thread1 , NULL ,produce(index_prod),( void *) m1);// The pthread_create() function starts a new thread in the calling process. //printf("erreur"); //pthread_join (thread1 ,NULL );//The pthread_join() function shall suspend execution of the calling thread until the target thread terminates, printf("herr"); pthread_create (&thread2,NULL,consume(index_cons),( void *) m2); //pthread_join(thread2,NULL); //pthread_join (thread1 ,NULL ); return 0; }
预期输出
produce : 13 consume : sort [1 elements ] = > 13 produce : 16 consume : sort [2 elements ] = > 16 13 produce : 27 consume : sort [3 elements ] = > 27 16 13 produce : 25 consume : sort [4 elements ] = > 27 25 16 13 produce : 23 consume : sort [5 elements ] = > 27 25 23 16 13
问题排查与修复点
1. 线程创建错误
pthread_create的第三个参数需要是函数指针,直接调用produce(index_prod)会导致主线程立即执行该函数,而非创建新线程。同时,线程函数的签名必须是void* (*)(void*),原代码中produce和consume的参数类型是int,不匹配。
修复:
- 修改线程函数参数为
void*,内部转换为线程索引 - 传递函数地址给
pthread_create,线程索引通过第四个参数传递
2. Peterson锁实现错误
原lock函数逻辑完全错误,不符合Peterson算法的正确步骤:
- 正确逻辑:当前线程标记自己想要进入临界区,然后让出优先级,最后等待对方线程不在临界区且优先级在对方时循环等待
- 原
unlock参数未声明类型,且未正确重置当前线程的进入标记
修复:
void lock(int index) { Veut_entrer[index] = 1; Tour = 1 - index; while (Veut_entrer[1 - index] == 1 && Tour == 1 - index) { // 空等待 } } void unlock(int index) { Veut_entrer[index] = 0; }
3. 生产者函数提前返回
produce函数的return (NULL);写在while循环内部,导致第一次生产后就直接退出,无法完成5次生产。
修复:将return移到while循环外部。
4. 消费者排序参数错误
qsort的第二个参数是实际元素个数,原代码用MAX_SIZE / sizeof(int)会把数组中未初始化的垃圾数据也加入排序,导致输出错误。
修复:改为size_tab。
5. 缺少线程同步与等待
- 消费者空轮询浪费CPU,且无法及时感知生产者的生产动作(可以用条件变量优化,这里先修复基础逻辑)
main函数创建线程后直接返回,导致进程提前退出,线程无法执行完成
修复:添加pthread_join等待两个线程执行完毕。
6. 全局变量初始化
size_tab未显式初始化,虽然全局变量默认值为0,但显式初始化更严谨。
修复后的完整代码
#define MAX_NUM 30 #include <pthread.h> #define MAX_SIZE 100 #include <stdio.h> #include <stdlib.h> #include <unistd.h> // 可选,用于模拟生产间隔 #include <time.h> int tab[MAX_SIZE]; int size_tab = 0; int Veut_entrer[2]; int Tour = 0; typedef unsigned int uint; void lock(int index) { Veut_entrer[index] = 1; Tour = 1 - index; while (Veut_entrer[1 - index] == 1 && Tour == 1 - index) { // 空等待 } } void unlock(int index) { Veut_entrer[index] = 0; } void* produce(void* arg) { int index = *(int*)arg; uint count = 0; while (count < 5) { // 进入临界区 lock(index); tab[size_tab++] = rand() % MAX_NUM; printf("produce : %d\n", tab[size_tab - 1]); // 退出临界区 unlock(index); count++; sleep(1); // 模拟生产耗时,让消费者有机会执行 } return NULL; } int compare(const void* a, const void* b) { int const* pa = (int const*)a; int const* pb = (int const*)b; return (*pb - *pa); } void* consume(void* arg) { int index = *(int*)arg; uint count = 0; while (count != 5) { if (count < size_tab) { // 进入临界区 lock(index); qsort(tab, size_tab, sizeof(int), compare); printf("consume : sort [%d elements] =>", size_tab); for (uint i = 0; i < size_tab; i++) { printf(" %d", tab[i]); } printf("\n"); count = size_tab; // 退出临界区 unlock(index); } // 减少空轮询消耗 usleep(100000); } return NULL; } void init() { Veut_entrer[0] = 0; Veut_entrer[1] = 0; srand(time(NULL)); // 初始化随机数种子 } int main() { int index_prod = 0; int index_cons = 1; pthread_t thread1; pthread_t thread2; init(); // 创建生产者线程 pthread_create(&thread1, NULL, produce, &index_prod); // 创建消费者线程 pthread_create(&thread2, NULL, consume, &index_cons); // 等待线程执行完毕 pthread_join(thread1, NULL); pthread_join(thread2, NULL); return 0; }
修复说明
- 线程创建改为传递函数地址和参数,符合pthread规范
- 修正Peterson锁的逻辑,确保临界区互斥
- 修复生产者提前返回问题,保证完成5次生产
- 修正qsort参数,只排序已生产的元素
- 添加线程等待,确保进程等待线程执行完毕
- 初始化随机数种子,保证每次运行生产不同的随机数
- 增加睡眠操作,让生产者和消费者的执行交替更明显,符合预期输出的节奏
内容的提问来源于stack exchange,提问作者TheEndOfTheCycle
相关产品推荐
相关产品推荐

