记住加锁操作一定尧放在sem_wait()的上面 否则可能导致死锁
sem_t p_sem;
sem_t m_sem;
p_sem 生产者的信号量
m_sem 消费者的信号量
生产者消费者
生产者生产自身的资源-1 sem_wait()
消费者的资源+1 生产者告诉消费者+1 生产者中调用sem_post()放入消费者的信号量
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
pthread_cond_t cond; // 条件变量,用于实现线程间通信
pthread_mutex_t mutex; // 互斥锁,保证在临界区代码执行时的原子性
sem_t p_sem;
sem_t m_sem;
// wait-1 post+1
typedef struct NODE
{
int num;
struct NODE *next;
} NODE;
NODE *head = NULL;
/**
* 生产者线程函数
* 该函数模拟生产者的行为,不断生产产品(节点),并将其加入到链表中
* @param arg 线程函数的参数,这里未使用
* @return NULL
*/
void *Producer(void *arg)
{
while (1) // 模拟永久循环以持续生产
{
// pthread_mutex_lock(&mutex); 不能放上面会导致死锁 // 加锁,进入临界区
sem_wait(&p_sem); // 检测里面的value 如果不为0 就生产 为0 阻塞
pthread_mutex_lock(&mutex);
NODE *newnode = (NODE *)malloc(sizeof(NODE)); // 生产一个新节点
newnode->num = rand() % 1000 + 1; // 为节点赋予随机值,模拟生产行为
newnode->next = head; // 将新节点链接到链表头部
head = newnode;
printf("生产者 id : %d 生产者 number: %d\n", pthread_self(), newnode->num);
// 打印生产信息,包括线程ID和节点值
// pthread_mutex_unlock(&mutex); // 解锁,退出临界区
// // 生产完毕唤醒消费者
// pthread_cond_signal(&cond);
/*
而在生产者-消费者模型中,是生产者负责唤醒消费者。
*/
pthread_mutex_unlock(&mutex);
/// 信号量之间为临界区
sem_post(&m_sem);
sleep(rand() % 3); // 模拟生产者生产速度
}
return NULL;
}
/**
* 消费者线程函数
* 函数模拟消费者的行为,不断从链表中消费产品(节点)
* @param arg 线程函数的参数,这里未使用
* @return NULL
*/
void *Maker(void *arg)
{
while (1) // 模拟永久循环以持续消费
{
// pthread_mutex_lock(&mutex); // 加锁,进入临界区
// while (head == NULL)
// {
// // 阻塞消费者线程,等待生产者信号
// pthread_cond_wait(&cond, &mutex);
// }
sem_wait(&m_sem);
pthread_mutex_lock(&mutex);
NODE *consumer = head;
head = head->next; // 更新 head 指针
printf("消费者 id : %d 消费者 number : %d\n", pthread_self(), consumer->num); // 打印消费信息,包括线程ID和节点值
free(consumer); // 释放已消费的节点内存
pthread_mutex_unlock(&mutex);
// pthread_mutex_unlock(&mutex); // 解锁,退出临界区
sem_post(&p_sem); // 消费成功通知生产者生产
sleep(rand() % 3); // 模拟消费者消费速度
}
return NULL;
}
int main(int argc, char const *argv[])
{
// pthread_cond_init(&cond, NULL);
// 生产者的value 不能为 0 否则 消费者会一直等待 消费者需要为0 阻塞 还没生产不能消费
sem_init(&p_sem, 0, 2); // 第二个参数为线程为0时表示线程同步
// value 为1的时候可以不用加锁 但是 多个生产者 就需要加锁了
sem_init(&m_sem, 0, 0);
/*
生产者最多只有一个工作
生产一个 通知消费者来消费
*/
pthread_mutex_init(&mutex, NULL);
// 定义生产者和消费者线程数量
pthread_t producer[5];
pthread_t maker[5];
for (int i = 0; i < 5; i++)
{
pthread_create(&producer[i], NULL, Producer, NULL); // 创建 5 个生产者线程
}
for (int i = 0; i < 5; i++)
{
pthread_create(&maker[i], NULL, Maker, NULL); // 创建 5 个消费者线程
}
// 等待所有线程执行完毕
for (int i = 0; i < 5; i++)
{
pthread_join(producer[i], NULL);
pthread_join(maker[i], NULL);
}
// pthread_mutex_destroy(&mutex);
// pthread_cond_destroy(&cond);
sem_destroy(&p_sem);
sem_destroy(&m_sem);
return 0;
}