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

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.结果

4.分析
为什么使用信号量:主要用于线程间的同步和资源计数,以协调不同线程的行为。
为什么使用互斥锁:主要用于保护共享资源,防止数据竞争和保证数据的一致性。
为什么使用条件变量:主要用于让线程在某个条件未达成时进入阻塞状态,等到条件满足之后再被唤醒。
使用该代码可以实现一直保持不会爆库存,同理,也不会让订单超出范围。
















