模型中,最为关键的步骤是,在生产者回调函数中,未生产之前,消费者回调函数是阻塞的,阻塞方式是条件变量。
那么不使用条件变量,如何使用“信号量”实现阻塞呢?
答案是因为调用 sem_wait,当 sem == 0 时候,该线程就会阻塞。因此:生产者对应一个信号量 :sem_t produce;消费者对应一个信号量 :sem_t customer。
sem_init(&produce, 0, 2);
sem_init(&customer, 0, 0); 消费者 value = 0,表示被阻塞
// 头文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
sem_t produce; // 定义2个信号量
sem_t custom;
typedef struct node // 定义共享变量结构体
{
int data;
struct node* next;
}Node;
Node* phead = NULL; // 头结点置空
// 生产者回调函数
void* produce_fun()
{
while(1)
{
sem_wait(&produce); // 生产者取信号量并生产
Node* node = (Node*)malloc(sizeof(Node));
node->data = rand() % 1000;
node->next = phead;
phead = node;
printf("生产者:%lu, 产品:%d\n", pthread_self(), node->data);
sem_post(&custom); // 给消费者信号量
sleep(1);
}
return NULL; }
// 消费者回调函数
void* custom_fun()
{
while(1)
{
sem_wait(&custom); // 刚开始消费者阻塞,直至生产者给消费者信号量后,解除阻塞
Node* del = phead; // 记录待删除头结点的位置
phead = phead->next; // 更新删除后新头结点
printf("消费者: %lu, 消费: %d\n", pthread_self(), del->data);
free(del); // 删除头结点
sem_post(&produce); // 归还信号量,回复阻塞状态
sleep(1);
}
return NULL; }
int main()
{
srand(time(NULL));
// 初始化信号量
sem_init(&produce, 0, 2);
sem_init(&custom, 0, 0);
// 创建线程
pthread_t p1, p2;
pthread_create(&p1, NULL, produce_fun, NULL);
pthread_create(&p2, NULL, custom_fun, NULL);
// 回收子线程
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// 销毁信号量
sem_destroy(&produce);
sem_destroy(&custom);
return 0;
}