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

生产者消费者问题实现遇阻:疑似陷入无限循环求排查

生产者消费者问题排查与修复

问题概述

尝试实现生产者消费者模型,程序疑似陷入无限循环,无法得到预期输出。需求是每生产一个元素,消费者就执行一次排序输出操作。

原始代码

#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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 04:33:15