1.前提

昨天,曹操的智能家居专卖店初步实现了基本的功能,即生产和消费,但是存在一些问题如下图,当库存满之后,再重新统计的时候会出现库存统计变为0的情况。

【生产者--消费者模型】曹操的智能家居专卖店(2)_C

2.解决方法

为了解决这个问题,简化了代码(去除了结构体的使用),减少了库存容量(方便观察)并添加了条件变量实现当库存满时等待。

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

#define MAX_STOCK 5    // 最大库存容量
#define MAX_ORDERS 50  // 最大待处理订单数
#define PRODUCER_NUM 3 // 生产者线程数
#define CONSUMER_NUM 5 // 消费者线程数

// 智能家居产品结构
typedef struct
{
    int id;
    char name[20];
    float price;
} SmartDevice;

// 库存管理
SmartDevice stock[MAX_STOCK];
int stock_head, stock_tail;
sem_t stock_empty, stock_full;                        // 信号量,资源计数
pthread_mutex_t stock_mutex;                          // 互斥锁,保护资源
pthread_cond_t stock_cond = PTHREAD_COND_INITIALIZER; // 条件变量,停止

// 订单队列
int orders[MAX_ORDERS];
int order_head, order_tail;
sem_t order_empty, order_full;                        // 信号量,资源计数
pthread_mutex_t order_mutex;                          // 互斥锁,保护资源
pthread_cond_t order_cond = PTHREAD_COND_INITIALIZER; // 条件变量,停止

// 系统控制
int running;

/* 初始化交易系统 */
void init_system()
{
    // 库存初始化
    stock_head = stock_tail = 0;
    sem_init(&stock_empty, 0, MAX_STOCK);
    sem_init(&stock_full, 0, 0);
    pthread_mutex_init(&stock_mutex, NULL);
    pthread_cond_init(&stock_cond, NULL);

    // 订单初始化
    order_head = order_tail = 0;
    sem_init(&order_empty, 0, MAX_ORDERS);
    sem_init(&order_full, 0, 0);
    pthread_mutex_init(&order_mutex, NULL);
    pthread_cond_init(&order_cond, NULL);

    // 开启系统
    running = 1;
}
/* 生产者线程 - 制造产品 */
void *producer(void *arg)
{
    int producer_id = *(int *)arg;
    while (running)
    {
        // 生产间隔
        sleep(1 + rand() % 2);

        pthread_mutex_lock(&stock_mutex);
        // 当库存满时等待
        while ((stock_tail + 1) % MAX_STOCK == stock_head)
        {
            pthread_cond_wait(&stock_cond, &stock_mutex);
        }

        pthread_mutex_unlock(&stock_mutex);

        // 等待空位
        sem_wait(&stock_empty);
        pthread_mutex_lock(&stock_mutex);

        // 生产产品
        SmartDevice device = {
            .id = rand() % 1000 + 1000,
            .price = 99.9 + rand() % 1000 * 0.1};
        sprintf(, "HomeAI-%04d", device.id);

        // 加入库存
        stock[stock_tail] = device;
        stock_tail = (stock_tail + 1) % MAX_STOCK;

        printf("[生产者%d] 生产 %s (¥%.1f)\n",
               producer_id, , device.price);

        pthread_mutex_unlock(&stock_mutex);
        sem_post(&stock_full);
    }
    return NULL;
}

/* 消费者线程 - 处理订单 */
void *consumer(void *arg)
{
    int consumer_id = *(int *)arg;
    while (running)
    {
        pthread_mutex_lock(&order_mutex);
        // 当订单满时,通知生产者可以生产
        if ((order_tail + 1) % MAX_ORDERS == order_head)
        {
            pthread_cond_broadcast(&stock_cond);
        }
        
        pthread_mutex_unlock(&order_mutex);

        // 等待订单
        sem_wait(&order_full);
        pthread_mutex_lock(&order_mutex);

        // 当没有订单,停下来等待直到有
        while ((order_head == order_tail) && running)
        {
            pthread_cond_wait(&order_cond, &order_mutex);
        }

        // 获取订单
        int order_id = orders[order_head];
        order_head = (order_head + 1) % MAX_ORDERS;

        pthread_mutex_unlock(&order_mutex);
        // 通知生产者可以生产了(如果有生产者在等待)
        pthread_cond_signal(&order_cond);
        sem_post(&order_empty);

        // 处理订单(等待库存)
        sem_wait(&stock_full);
        pthread_mutex_lock(&stock_mutex);

        // 当没有商品,停下来等待直到有
        while ((stock_head == stock_tail) && running)
        {
            pthread_cond_wait(&stock_cond, &stock_mutex);
        }

        // 获取商品
        SmartDevice device = stock[stock_head];
        stock_head = (stock_head + 1) % MAX_STOCK;

        printf("[消费者%d] 完成订单#%04d:%s (¥%.1f)\n",
               consumer_id, order_id, , device.price);

        pthread_mutex_unlock(&stock_mutex);
        // 通知生产者可以生产了(如果有生产者在等待)
        pthread_cond_signal(&stock_cond);
        sem_post(&stock_empty);

        // 处理时间
        sleep(1 + rand() % 3);
    }
    return NULL;
}

/* 订单生成线程 */
void *order_generator(void *arg)
{
    int order_id = 0;
    while (running)
    {
        sleep(1 + rand() % 2);

        sem_wait(&order_empty);
        pthread_mutex_lock(&order_mutex);

        orders[order_tail] = ++order_id;
        order_tail = (order_tail + 1) % MAX_ORDERS;

        printf("[系统] 新订单到达 #%04d\n", order_id);

        pthread_mutex_unlock(&order_mutex);
        sem_post(&order_full);
    }
    return NULL;
}

/* 监控线程 */
void *monitor(void *arg)
{
    while (running)
    {
        sleep(5);
        printf("\n=== 系统状态监控 ===\n");
        printf("当前库存:%d/%d\n",
               (stock_tail - stock_head + MAX_STOCK) % MAX_STOCK,
               MAX_STOCK);
        printf("待处理订单:%d/%d\n\n",
               (order_tail - order_head + MAX_ORDERS) % MAX_ORDERS,
               MAX_ORDERS);
    }
    return NULL;
}

int main()
{
    srand(time(NULL));
    init_system();

    pthread_t producers[PRODUCER_NUM];
    pthread_t consumers[CONSUMER_NUM];
    pthread_t order_thread, monitor_thread;

    // 创建生产者
    int producer_ids[PRODUCER_NUM];
    for (int i = 0; i < PRODUCER_NUM; i++)
    {
        producer_ids[i] = i + 1;
        pthread_create(&producers[i], NULL, producer, &producer_ids[i]);
    }

    // 创建消费者
    int consumer_ids[CONSUMER_NUM];
    for (int i = 0; i < CONSUMER_NUM; i++)
    {
        consumer_ids[i] = i + 1;
        pthread_create(&consumers[i], NULL, consumer, &consumer_ids[i]);
    }

    // 创建辅助线程
    pthread_create(&order_thread, NULL, order_generator, NULL);
    pthread_create(&monitor_thread, NULL, monitor, NULL);

    // 运行3秒后关闭系统
    // sleep(3);
    // running = 0;

    // 等待线程结束
    for (int i = 0; i < PRODUCER_NUM; i++)
        pthread_join(producers[i], NULL);
    for (int i = 0; i < CONSUMER_NUM; i++)
        pthread_join(consumers[i], NULL);
    pthread_join(order_thread, NULL);
    pthread_join(monitor_thread, NULL);

    // 销毁同步对象
    sem_destroy(&stock_empty);
    sem_destroy(&stock_full);
    sem_destroy(&order_empty);
    sem_destroy(&order_full);
    pthread_mutex_destroy(&stock_mutex);
    pthread_mutex_destroy(&order_mutex);
    pthread_cond_destroy(&stock_cond);
    pthread_cond_destroy(&order_cond);

    printf("\n=== 系统已安全关闭 ===\n");
    return 0;
}


3.结果

【生产者--消费者模型】曹操的智能家居专卖店(2)_生产者-消费者模型_02

4.分析

为什么使用信号量:主要用于线程间的同步和资源计数,以协调不同线程的行为。

为什么使用互斥锁:主要用于保护共享资源,防止数据竞争和保证数据的一致性。

为什么使用条件变量:主要用于让线程在某个条件未达成时进入阻塞状态,等到条件满足之后再被唤醒。

使用该代码可以实现一直保持不会爆库存,同理,也不会让订单超出范围。